I simply want to use a data that has been calculated in a child component and also use the same data in my parent component. How do i do so? This is my current approach, it works but i get this error:
Cannot update a component from inside the function body of a different component
Please suggest a correct method.
Parent:
const Parent = () => {
const [myValue, setMyValue] = useState("");
const getValue = (value) => {
setMyValue(value);
};
return (
<div className={styles.innerContainer}>
<div className={styles.introPara}>{myValue}</div>
<Child passToParent={getValue} />
</div>
);
};
export default Parent;
Child
const Child = ({ passToParent }) => {
let url = "www.google.com";
const findUrl = () => {
return url;
};
let finalValue = findUrl();
const finalText = finalValue.toUpperCase();
passToParent(finalText);
return (
<div>
<a href={finalValue}>
<div>{finalText}</div>
</a>
</div>
);
};
export default Child;
I want to use the finalText in both Child and Parent components but i don't want to repeat the logic i'm using in finalUrl( ). Currently i'm simply using passToParent( ) and it works but gives error.
try this - just pass myValue - instead getFunction:
getValue - this is the function - it's should be triggered on some user actions eg. onClick, onMouseEnter etc.
You hold myValue in useState reactHook - it's type: string
In child u destructurizing props - so there is option just to write it without processing.
Also there is possibility to pass function to child component
const Parent = () => {
const [myValue, setMyValue] = useState("");
const getValue = (value) => {
setMyValue(value);
};
return (
<div>
<Child passToParent={myValue} />
</div>
);
};
export default Parent;
const Child = ({ passToParent }) => {
return (
<div>
<a>
<div>{passToParent}</div>
</a>
</div>
);
};
export default Child;
Related
i want to pass the data of text-input from child to parent to submit the dynamic form. when i use useEffect the phone blocked but i don't know why.please can someone help me to solve this problem.thanks to tell me if there are another way to pass the data.
child component
const RenderComponents = ({ sendChildToParent) => {
const [inputsVal, setInputsVal] = useState({});
const handleChange = (name, value) => {
setInputsVal({ ...inputsVal, [name]: value });
};
const senddata = () => {
sendChildToParent(inputsVal);
};
useEffect(senddata);
return (
<>
{getData.length === 0 ? (
<Empty />
) : (
getData.map((item, index) => {
switch (item.type) {
case "TextInput":
return (
<>
<InputText
onChangeText={(text) => handleChange(item.nameC, text)}
ModuleName={item.nameC}
placeholder={item.options.placeholder}
required={item.options.required}
key={index}
/>
</>
);
case "Phone":...
Parent Component
export function TemplateScreen(props) {
const navigation = useNavigation();
const [getData, setData] = React.useState(Mydata);
const [childData, setChildData] = useState([]);
const sendChildToParent = (dataFromChild) => {
setChildData(dataFromChild);
};
//*************************************Child Componenet*************** */
const RenderComponents = () => {
const [userTeam, setUserTeam] = useState({});
[...other code here...];
**********Parent Component*******
return (
<ScrollView>
<RenderComponents />
<Button
title="Submit"
onPress={()=>null}
/>...
The structure of your parent component is fine. The issues are in your child component, in the following lines:
const RenderComponents = ({ sendChildToParent) => {
const [inputsVal, setInputsVal] = useState({});
const handleChange = (name, value) => {
setInputsVal({ ...inputsVal, [name]: value });
};
const senddata = () => {
sendChildToParent(inputsVal);
};
useEffect(senddata);
it's not good practice to duplicate the input value in local state. Pass the value down from the parent component as well as the setter function.
you're not passing a dependency array to your useEffect function, so it runs on every render of the component. This sets off the following chain of events:
the parent renders
the child renders
useEffect runs, setting the value of the state in the parent
the parent re-renders
This is an endless loop and what causes your app to lock.
there's no need to wrap the state setting functions in your own functions unless you are planning to do additional work there later. There's also no need to run those functions in your component lifecycle (useEffect), because they will run when the input changes.
missing bracket in the first line.
You could rewrite the components in the following way:
// parent component
export function TemplateScreen(props) {
const navigation = useNavigation();
const [getData, setData] = React.useState(Mydata);
const [childData, setChildData] = useState({});
return (
<ScrollView>
<RenderComponents childData={childData} setChildData={setChildData} />
...
// child component
const RenderComponents = ({ childData, setChildData }) => {
const handleChange = (name, value) => {
setChildData({ ...childData, [name]: value });
};
return (
...
in child component I want to update the state when user clicked on button available in parent component and I've keep track of state value as this state is also affect by other code as well so I was thinking to use useEffect() hook but I'm not sure how to achieve it.
child component:
const [sentimentButtonValue, setSentimentButtonValue] = useState(false);
return(
<>
{sentimentButtonValue}
</>
)
parent Component:
const handelTableCardOpen = (idx) => {
// when this function call, want to update child 'sentimentButtonValue' state value
console.log(idx);
setSelectedRow(idx);
};
<Button key={idx} onClick={() => handelTableCardOpen (idx)}> Click </Button>
as others have stated, you need to life the state up, BUT JUST IN CASE you have a special case where you really need it
const Child = React.forwardRef((_, ref) => {
const [sentimentButtonValue, setSentimentButtonValue] = React.useState(false);
React.useImperativeHandle(ref, () => ({
whatEver: sentimentButtonValue,
setWhatEver: setSentimentButtonValue,
}));
return <>{sentimentButtonValue.toString()}</>;
});
const Parent = () => {
const childRef = React.useRef();
const handelTableCardOpen = () => {
childRef.current.setWhatEver(!childRef.current.whatEver);
};
return (
<>
<button onClick={handelTableCardOpen}>Click</button>
<Child ref={childRef} />
</>
);
};
You need to lift the state from the child to the parent component, and then pass that state as a prop to the child:
const Parent = () => {
const [sentimentButtonValue, setSentimentButtonValue] = useState(false)
const yourFunction = () => {
setSentimentButtonValue(newValue);
}
<Button
sentimentButtonValue={sentimentButtonValue}
onClick={yourFunction}
>
Click
</Button>
}
I have a logic in my code that i don't understand, i can update a state (useState) throught my child components but without the "set" function.
Here is my (simplified) code :
const Main = () =>{
const [mission, setMission] = useState({activity:"", env:""})
const see = () =>{
console.log(mission)
}
return (
<Child1 data={mission} />
<button onClick={see}>TEST</button>
)
}
const Child1 = (props) =>{
const {data} = props
const [mission, setMission] = useState(data)
const handleChange = (value) =>{
mission["activity"] = value
}
return (
<Child2 data={mission} onChange={handleChange} />
)
}
const Child2 = (props) =>{
const {data} = props
const [activity, setActivity] = useState(data.activity)
const handleChange = (e) =>{
setActivity(e.target.value)
props.onChange(e.target.value)
}
return (
<input value={data} onChange={handleChange} />
)
}
I tried in sandbox and it work too, "mission" did update it's value throught all childs without any "setMission".
I'm relativily new to react so i miss something but i don't know what, can someone explain ?
Thank you
You probably want to "lift the state up". Only the Main component should useState. Then pass both the state value and update function to the child component. The child component will call this update function when it updates. This will update the state on the parent properly and re-render.
Using your example:
const Main = () => {
// Only one state at the top level
const [mission, setMission] = useState({ activity: "", env: "" });
const see = () => {
console.log(mission);
};
return (
<>
{/* Pass both the value and state update function to the child */}
<Child1 data={mission} update={setMission} />
<button onClick={see}>TEST</button>
<div>{mission.activity}</div>
</>
);
};
const Child1 = (props) => {
const { data, update } = props;
const handleChange = (e) => {
// This will set parent's state
update({ ...data, activity: e.target.value });
};
// You can follow the similar pattern to the next child
return <Child2 data={data} onChange={handleChange} />;
};
You can see a complete working example in this sandbox.
I have a parent component that is fetching data from an api, I would like to fetch it once on render and set it to state and pass it down as props to a child component that will then map over this state. How can I wait for 'bids' to have items before the child component renders? I thought by passing setBids it would wait until bids is set, but instead im getting an empty array to map over
function Parent () {
const [bids, setBids] = useState([]);
useEffect(() => {
const fetchBids = async () => {
const result = await api.GetBids();
setBids(result.body);
};
fetchBids();
}, [ setBids ]);
return ( <Child bids={bids}/>)
}
export default Parent;
function Child(props) {
const { bids, id } = props;
return (
<Fragment>
{bids.map((responseBidId) => {
if (responseBidId === id) {
return (
<button onClick={handleView}>view</button>
);
} else {
return (
<Button
onClick={handleUpload}
>
Upload
</Button>
);
}
})}
</Fragment>
);
}
export default Child;
You could wait for bids to be populated before rendering the child:
const [bids, setBids] = useState();
return bids ? <Child bids={bids}/> : null;
You can't "wait", not really. If you think about it more in terms of "when" should I render the child it might help though.
function Parent () {
const [bids, setBids] = useState(null); // <-- change to null to indicate unset
useEffect(() => {
const fetchBids = async () => {
const result = await api.GetBids();
setBids(result.body);
};
fetchBids();
}, [ setBids ]);
return bids ? <Child bids={bids}/> : null;
}
export default Parent;
I'm trying to pass child data to parent on an onClick event that happens in a parent button.
I have a basic mock defined below to explain what I'm trying to achieve.
const Parent = () => {
const childData = (data) => {
console.log(data);
}
const receiveData = () => {
childData();
}
return (
<>
<button onClick={receiveData}>Receive Child Data</button>
<Child onParentClick={childData} />
</>
)
}
const Child = ({onParentClick}) => {
// Trigger onParentClick here to pass some data to parent
return (
// something
)
}
How can I achieve this?
class Parent extends Component {
passDataToParent = data => {
console.log(data);
}
render() {
return (
<Child passDataToParent={this.passDataToParent} />
);
}
}
const Child = props => {
buttonClick = () => {
const data = {
a: 1
};
props.passDataToParent(data);
};
return (
<Button onClick={buttonClick} />
)
}
You can do something like this with callbacks (this example is using hooks)..
Edit: this does feel like an 'anti-pattern' to me though... It has been my understanding that React is meant for one way data flow from the top down.. (eg. why this is so tricky to accomplish, use of 'higher order components', etc..).. Furthermore, this doesn't necessarily "pass" data up to the parent.. it would be more appropriate to say 'a reference to a child function is being passed to the parent'.. the parent just calls the child function. Meaning "data" is not passed, rather the function itself.. Please correct me if I am wrong... I am fairly new to React. Finally, I do not understand the use case for something like this -- in which scenario does one need to use this "paradigm"?
[CodePen Mirror]
// Parent
const Parent = () => {
let child;
function getChildData(callbacks){
child = callbacks;
}
return (
<div>
<button onClick={() => child.getData()}>Retreive Child Data</button>
<Child onRetreiveChildData={callbacks => getChildData(callbacks)} />
</div>
);
}
// Child
const Child = ({ onRetreiveChildData }) => {
const [state, setState] = React.useState({
data: "Default Child Data"
});
if (onRetreiveChildData) {
onRetreiveChildData({
getData: () => getData("Data from Child: " + Math.random())
});
}
function getData(data){
setState({ data: data });
};
return (
<pre>{state.data}</pre>
)
};
ReactDOM.render(<Parent />, document.getElementById("root"));
<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' style='width: 100%; height: 100%'>
</div>