React container props child passing - reactjs

afraid that question is simple stupid but im stuck(
I have a Box component with some nested ones:
<Box.Content anyProp="prop">
<Box.Text...
<Box.Links
How I can pass ALL the props form Box.Content to ALL child containers (Box.Text, Box.Links, anything else)?
Trying with no luck:
BoxComponent.Content = (...props) => (
<BoxContent {...props}>{props.children}</BoxContent>
);
Then trying to catch any prop from Parent inside child container - no props listed(

You can use React.cloneElement to dynamically set a parent's props on its children.
Run the following code snippet. prop1 and prop2 on the Parent component are passed to the Child1 and Child2 components.
const Child1 = (props) => <p>Child 1: {JSON.stringify(props)}</p>;
const Child2 = (props) => <p>Child 2: {JSON.stringify(props)}</p>;
const Parent = ({ children, ...props }) => {
children = children.map(v => React.cloneElement(v, props));
return <div id="parent">{children}</div>;
};
const App = () => (
<Parent prop1="foo" prop2="bar">
<Child1 />
<Child2 />
</Parent>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>

Related

Get Root DOM element from a child component

I have a loop that reads multiple elements from the document and I render it with ReactDOM.render, and a component very low in the component tree, creates a custom event, to that event I would like to pass the element that was rendered in the DOM (i.e. Root Element), I have to go passing from the top the element through Props, or React provides some API that can tell me which Root element we are?
Rather, in the child component, I would like to make: rootElement.dispatchEvent(myCustomEvent);
What options do I have to do this?
The root node looks to be given a property that starts with __reactContainer, so you can search through parent elements until you find an element with such a property.
const Child = () => <div><span onClick={(e) => {
let element = e.target;
while (element) {
element = element.parentElement;
if (Object.keys(element).some(key => key.includes('reactContainer'))) {
console.log('Found', element);
break;
}
}
}}>click</span></div>;
const App = () => {
return <section><Child /></section>
};
ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div class='react'></div>
That's almost certainly not part of the deliberate outward-facing design, though. A better way would be to use useContext to save the root element at the top component via a ref, and to consume it in the descendant component.
const Child = () => {
const { ref } = React.useContext(Context);
return (
<div>
<span
onClick={() => { console.log(ref.current.parentElement); }}
>click</span>
</div>
);
};
const Context = React.createContext();
const App = () => {
const ref = React.useRef();
return (
<Context.Provider value={{ref}}>
<section ref={ref}><Child /></section>
</Context.Provider>
);
};
ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div class='react'></div>

Make child component re-render without sending useless props

I'm changing state inside of the parent component:
this.setState({ langIndex: 0 });
The parent component re-renders correctly. But it's child do not re-render unless I pass the state from the parent as props to them:
<LoginForm langIndex={this.state.langIndex} />
Now langIndex is useless inside of LoginForm but I need stuff to re-render inside of it nonetheless. Is there any 'clean' way of doing so ?
As you mentioned in one of your comments that you are using i18next:
There are react bindings for i18next that enable re-rendering on language change if that is what you want. They work by subscribing to the i18next store and triggering a state change on language change.
You can use the useTranslation hook:
function MyComponent() {
const { t, i18n } = useTranslation();
// or const [t, i18n] = useTranslation();
return <p>{t('my translated text')}</p>
}
or the WithTranslation HOC:
function MyComponent({ t, i18n }) {
return <p>{t('my translated text')}</p>
}
export default withTranslation()(MyComponent);
Calling i18n.changeLanguage() will trigger a re-render.
If your problem is that you need to pass data from a Parent to a grand child (or several levels down the tree) and you don't want to pass it through all levels (usually called as prop drilling), then you can use react context to skip levels
Here is a running example:
const MyContext = React.createContext(null);
const Child = () => {
const value = React.useContext(MyContext);
return <div>{`in child... ${value}`}</div>;
};
const Parent = () => <Child />;
function App() {
const [value, setValue] = React.useState("");
return (
<MyContext.Provider value={value}>
<div>App</div>
<input value={value} onChange={e => setValue(e.target.value)} />
<Parent />
</MyContext.Provider>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

Take a string but need react component

I have some object like:
'key': { a: 'aa', b:'bb', c: <Component/> }
It object returned as property in some object:
{item.a}
{item.b}
{item.c}
item.c - is a string, but im need take real component in render. Very thanks for any answer!!!
You would convert your values to arrow functions.
Working example :
const data = {
a: () => 'aa',
b: () => 'bb',
c: () => <Component />
}
const App = props =>
<div>
{data.a()}
{data.b()}
{data.c()}
</div>
const Component = props => <p>Comp</p>
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>
<div id='root'>
Simply storing your component in a variable will also* work :
const Component = props => <p>Comp</p>
const data = {
a: 'aa',
b: 'bb',
c: <Component />
}
const App = props =>
<div>
{data.a}
{data.b}
{data.c}
</div>
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>
<div id='root'>
It should work without any magic, Component here is a function and calling item.c should give you the reference to the function. Double check your code, if it doesn't work then you need to provide more details like how you are calling it.

How do I programmatically set focus on an element in a different component in React?

I have a parent component and two child components, call them child A and child B. I want to click a button in child A that will set focus on an element in child B. More specifically, I want to set focus on the first element under the <main> tag in child B.
How do I do so? Do I have to use React.createRef() in the parent and then pass that reference to both children or is there a more straightforward way to do this?
Creating a ref in the parent component like you mentioned and passing that to child B, and creating a function that will focus the ref and passing that to child A is one way of approaching it.
Example
class App extends React.Component {
ref = React.createRef();
handleClick = () => {
this.ref.current.focus();
};
render() {
return (
<div>
<ChildA onClick={this.handleClick} />
<ChildB innerRef={this.ref} />
</div>
);
}
}
function ChildA(props) {
return <button onClick={props.onClick}>Focus</button>;
}
function ChildB(props) {
return <input ref={props.innerRef} />;
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>

React props from parent to children

I'm a debutant with react, i read the doc. It's a general question.
I understand how to pass a props from a child component to a parent component. But, I don't understand how to pass a props from a parent component to the child component.
So in the picture, to pass a props from list to app, i do that :
in list component :
interface Props {
onCreateDoc : () => void
}
And in my app component :
I call list with the props :
<List onCreateDoc={this.onCreateDocCb}/>
And i implement the function :
onCreateDocCb = () =>{
// code of function
}
But I don't know how to pass a props from app to form. How can i do that ? Thank you
It's easier to understand how to pass props then how to receive props.
You add props to your Form Component that way:
const bar = "bar"
const fooBar = () => console.log("fooBar")
<Form stringProps="foo" varProps={bar} funcProps={fooBar}/>
Inside your Form Component you can acces it via this.props.stringProps.
Here you find examples: https://facebook.github.io/react/docs/components-and-props.html
Edit: Here is a snippet with a App and a Form Component and props passed from App to Form
// Example stateless functional component
const Form = ({ label }) => (
<div style={{color: "blue"}}>{label}</div>
);
// Example class component
class App extends React.Component {
render() {
const {title} = this.props;
return (
<div>
<div>{title}</div>
<Form label="label from props" />
</div>
);
}
}
// Render it
ReactDOM.render(
<App title="title from props" />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Resources