pretty simple but confused,
i have one parent component with state as
this is my
this.state = {
todoName: "",
todoList: [],
"isAvail":true,
"IsArchive":false
};
and inside my parent component i am calling child component
<ChildComponent data= {this.state} />
but in childCompoenent inside the render i try to call like
const isAvail = this.props.data.isAvail;
const isArchieve = this.props.data.isArchieve;
and inside retrun if i call like this am {isAvail} am not getting and am getting error
Objects are not valid as a React child (found: object with keys {todoName, todoList, isAvail, IsArchive}). If you meant to render a collection of children, use an array instead.
But somehow i need to get full object..How is it possible
You may call like this one
render() {
const {isAvail, isArchieve} = this.props.data;
return(<div><p>{isAvail}</p></div>);
}
class Parent extends React.Component{
constructor(props){
super(props)
this.state= {
todoName: "passed from parent", todoList: [], "isAvail":true, "IsArchive":false
}
}
render(){
return <Child data={this.state}/>
}
}
const Child = (props) => <div>{props.data.todoName}{console.log(props)}</div>
Live Demo
Do you know ContextAPI & you want to send data without using props drilling useContextAPI. In some cases we can use state values in to childcomponents also in using context API.
In your parent component create context
const ParentState = React.createContext()
render() {
<ParentState.Provider value={{ data: this.state }}>
<Childcomponent/>
</ParentState.Provider>
}
In Child component import Context and use
render() {
return(
<ParentState.Consumer>
{
parentState => (<div><p>{parentState.data.isAvail}</p></div>)
}
</ParentState.Consumer>
)
}
Related
My React structure is
- App
|--SelectStudy
|--ParticipantsTable
In SelectStudy there is a button whose click triggers a message to its sibling, ParticipantsTable, via the App parent. The first Child->Parent transfer works. But how do I implement the second Parent->Child transfer? See questions in comments.
App
class App extends Component {
myCallback(dataFromChild) {
// This callback receives changes from SelectStudy Child Component's button click
// THIS WORKS
alert('SelectStudy Component sent value to Parent (App): ' + dataFromChild.label + " -> " + dataFromChild.value);
// QUESTION: How to Update State of ParticipantsTable (SelectStudy's Sibling) next?
// ........................................................
}
render() {
return (
<div className="App">
<SelectStudy callbackFromParent={this.myCallback}></SelectStudy>
<ParticipantsTable></ParticipantsTable>
</div>
);
}
SelectStudy
class SelectStudy extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
items: [],
selectedStudy: null,
isButtonLoading: false
};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
render() {
const { error, isLoaded, items, itemsForReactSelect, selectedStudy, isButtonLoading } = this.state;
return <Button onClick={this.handleButtonClick}>Search</Button>;
}
handleButtonClick = () => {
this.props.callbackFromParent(this.state.selectedStudy);
}
}
ParticipantsTable - this needs to receive a certain variable, e.g. study in its State
class ParticipantsTable extends React.Component {
constructor(props) {
//alert('Constructor');
super(props);
// Initial Definition of this component's state
this.state = {
study: null,
items: [],
error: null
};
}
// THIS METHOD IS AVAILABLE, BUT HOW TO CALL IT FROM App's myCallback(dataFromChild)?
setStudy = (selectedStudy) => {
this.setState({study: selectedStudy});
}
render() {
return ( <div>{this.state.study}</div> );
}
}
The state should live definitively at the App level, not in the child. State needs to live one level above the lowest common denominator that needs access to it. So if both SelectStudy and ParticipantsTable need access to the same bit of state data, then it must live in their closest common ancestor (or above).
This is a core concept of React, known as "lifting state up", so much so that it has its own page in the official React documentation.
In your case, it would look something like this. Notice how state lives in only one place, at the <App /> level, and is passed to children via props.
import React from 'react';
class App extends React.Component {
// State lives here at the closest common ancestor of children that need it
state = {
error: null,
isLoaded: false,
items: [],
selectedStudy: null,
isButtonLoading: false
};
myCallback = (dataFromChild) => {
this.setState(dataFromChild);
};
render() {
return (
<div className="App">
{/* State is passed into child components here, as props */}
<SelectStudy data={this.state} callbackFromParent={this.myCallback}></SelectStudy>
<ParticipantsTable study={this.state.selectedStudy} />
</div>
);
}
}
class SelectStudy extends React.Component {
handleButtonClick = () => {
// Here we execute a callback, provided by <App />, to update state one level up
this.props.callbackFromParent({ ...this.props.selectedStudy, isButtonLoading: true });
};
render() {
const { error, isLoaded, items, itemsForReactSelect, selectedStudy, isButtonLoading } = this.props.data;
return <Button onClick={this.handleButtonClick}>Search</Button>;
}
}
// This component doesn't need to track any internal state - it only renders what is given via props
class ParticipantsTable extends React.Component {
render() {
return <div>{this.props.study}</div>;
}
}
I think what you need to understand is the difference between state and props.
state is internal to a component while props are passed down from parents to children
Here is a in-depth answer
So you want to set a state in the parent that you can pass as props to children
1 set state in the parent
this.state = {
value: null
}
myCallback(dataFromChild) {
this.setState({value: dataFromChild.value})
}
2 pass it as a prop to the children
class ParticipantsTable extends React.Component {
constructor(props) {
super(props);
this.state = {
study: props.study,
items: [],
error: null
};
}
Also, although not related to your question, if you learning React I suggest moving away from class-based components in favour of hooks and functional components as they have become more widely used and popular recently.
I have two components, the first component is the 'select language' component for example he is a Provider and the second component is for example the 'login' component as the consumer I want to take the value that has been shared from the provider how to take that value? the thing is when I console the valuation at the login component is undifined
this is my provider
in this component there are no problems
import MyContext from './MyContext'
export class SelectLanguage extends Component {
constructor(props){
super(props)
this.state = {
loading:true,
pages:''
};
this.handleChange = this.handleChange.bind(this)
}
}
componentDidMount(){
const getCodeFromLocal = this.props.resGet('lang-code')||'RUWT-EN';
Api.post('pages-content', {CODE:getCodeFromLocal})
.then((response) => {
if(response.data.STATUS_CODE === '200'){
this.setState({
loading:false,
pages:response.data.DATA
});
}
})
}
}
render() {
const {language,loading,code,pages} = this.state
if(loading){
return(
<p>loading...</p>
)
}else{
return (
<MyContext.Provider value={pages}>
<Form.Group controlId="selectLanguage">
<Form.Label><b>{pages.app_setting.language}</b></Form.Label>
<Form.Control as="select" ref="selectLanguage" onChange={this.handleChange} value={code}>
{language.map(data => {
return(
<React.Fragment key={data.language_id}>
<option value={data.code}>{data.language_name}</option>
</React.Fragment>
)
})}
</Form.Control>
</Form.Group>
</MyContext.Provider>
)
}
}
this is my consumer/static context
export class Login extends Component {
constructor(props){
super(props)
this.state = {
about:[]
};
}
}
static contextType = MyContext;
render() {
let value = this.context
console.log(value)
return(<p>tes</p>)
}
why value undefined?
even though when I console at the data provider it appears
There are multiple ways to get the context values:
1) Use static contextType:
let value = this.context; // checks for the context type static declaration below
MyClass.contextType = MyContext; // You already have done this
Drawback : You can use only one context type to its binding.
As you wanted to know: First you bind whats the context type value you have. Application might have more context types. So you are saying that I need to bind this context(Note that it's static so it bound before the instance is created for class) and you access the value after instantiated , inside the class.
Your code:
export class SelectLanguage extends Component {
constructor(props){
super(props)
this.state = {
loading:true,
pages:''
};
this.handleChange = this.handleChange.bind(this)
}
.
.
}
.
.
.
// For example you can use in componentDidMount()
componentDidMount() {
let contextValue = this.context;
}
.
.
.
MyClass.contextType = MyContext;
}
2) Use Context's Consumer
Wrap your component with Consumer and use as props:
<MyContext.Consumer>
{value =>
<Foo bar={value}/>
}
</MyContext.Consumer>
Advantage: You can wrap multiple nested consumers and use accordingly.
3) React hook - useContext (Functional components only)
const Foo = () => {
const myContextValue = useContext(MyContext);
const user = useContext(UserContext);
return (<h5>I used hooks for {myContextValue} for user {user}</h5>);
}
Advantage: Obviously cleaner and no wrapper hell and plug and play concept.
I have use your code and make some changes in codesandbox. check https://codesandbox.io/s/keen-cray-in0km
Use React.useContext if you want to use context value outside of render method or just wrap login render with MyContext.Consumer
This app is supposed to filter words by a specific input. I want to call a function with setState() when rendering a component and technically it's working but there is warning in the console.
Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.
I guess that this is because I'm calling the function in the render function which I shouldn't, but what should I do instead?
class UsersList extends React.Component {
constructor(props) {
super(props);
this.state = {
allUsers: ["Michał", "Ania", "Kasia", "Tomek", "Hubert", "Jan", "Martyna", "Rafał", "Bartłomiej"],
filteredUsers: [],
input: null
}
}
filter() {
if (this.state.input !== this.props.inputValue) {
const filtered = this.state.allUsers.filter(user => user.toLowerCase().includes(this.props.inputValue));
this.setState({
filteredUsers: filtered.map(user => <li key={user}>{user}</li>),
input: this.props.inputValue
})
}
return this.state.filteredUsers;
}
render() {
this.filter()
return (
<ul>
{this.state.filteredUsers}
</ul>
)
}
}
class App extends React.Component {
constructor() {
super();
this.state = {input: ""};
this.handleInput = this.handleInput.bind(this);
}
handleInput(e) {
this.setState({input: e.target.value})
}
render() {
return (
<div>
<input onChange={this.handleInput} type="search"/>
<UsersList inputValue={this.state.input} />
</div>
);
}
}
The issue here is caused by changes being made to your component's state during rendering.
You should avoid setting component state directly during a components render() function (this is happening when you call filter() during your component's render() function).
Instead, consider updating the state of your component only as needed (ie when the inputValue prop changes). The recommended way to update state when prop values change is via the getDerivedStateFromProps() component life cycle hook.
Here's an example of how you could make use of this hook for your component:
class UsersList extends React.Component {
constructor(props) {
super(props);
this.state = {
allUsers: ["Michał", "Ania", "Kasia", "Tomek",
"Hubert", "Jan", "Martyna", "Rafał",
"Bartłomiej"],
filteredUsers: [],
input: null
}
}
/* Add this life cycle hook, it replaces filter(). Props are updated/incoming
props, state is current state of component instance */
static getDerivedStateFromProps(props, state) {
// The condition for prop changes that trigger an update
if(state.input !== props.inputValue) {
const filtered = state.allUsers.filter(user => user.toLowerCase().includes(props.inputValue));
/* Return the new state object seeing props triggered an update */
return {
allUsers: state.allUsers
filteredUsers: filtered.map(user => <li key={user}>{user}</li>),
input: props.inputValue
}
}
/* No update needed */
return null;
}
render() {
return (<ul>{this.state.filteredUsers}</ul>)
}
}
Hope this helps
The error is coming up as it could create an endless loop inside the component. As render method is executed whenever the state is updated and your function this.filter is doing a state update. Now as the state updates, your render method triggers the function again.
Best way to do that would be in lifecycle methods or maintain the uses in the App and make UserList a dumb component by always passing the list of filtered users for it to display.
I have a simple functional component
const Hello = (props) => <div>{props.name}</div>
How can I supply a stream of values to the props parameter and make the component update in reactive fashion, consuming the stream? So that every time the new value comes from the stream, I get the component updated with that value.
Basically I am looking for a way to manually re-render the component.
You can use two basic methods:
Component rerendering, which you mentioned
State system: https://facebook.github.io/react/docs/state-and-lifecycle.html
The second way could look like this:
const Hello = (props) => <div>{props.name}</div>
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
name: ''
};
}
componentDidMount() {
source.on('event', name => {
this.setState({name});
});
}
render() {
return <Hello name=this.state.name/>;
}
}
Please see the example here http://jsfiddle.net/8xzxkteu/1/
I'm trying to only render part of the data which is changed. In this example, state of component Main, data, is indexed by id and I am using react immutability helper to set only the changed one. But, if you click on the output, it renders all the children, as indicated by the counter. I though using immutability helper react can detect only part of the data changed hence only render it. I probably could use shouldComponentUpdate and compare object values for each child, but is there a better way doing this with immutability helper.
class Child extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this)
this.state = {
count: 0
};
}
componentWillReceiveProps(nextProps) {
var count = this.state.count + 1;
this.setState({ count: count });
}
onClick() {
this.props.onClick(this.props.name);
}
render() {
return <p onClick={this.onClick}>{this.props.name}: {this.props.value} {this.state.count}</p>;
}
}
class Main extends React.Component{
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this)
this.state = {
data: {
"a" : "a",
"b" : "b",
}
};
}
handleChange(id) {
this.setState({
data: React.addons.update(this.state.data, { [id]: { $set: 'x' } })
});
}
render() {
const keys = Object.keys(this.state.data);
const children = keys.map(k => {
return <Child name={k} value={this.state.data[k]} onClick={this.handleChange}/>
})
return <div>
{children}
</div>;
}
}
React.render(<Main />, document.getElementById('container'));
When you change state of component react call shouldComponentUpdate of this component and if it is return true react call render of this component.
After that react call componentWillReceiveProps, then shouldComponentUpdate, then render (if shouldComponentUpdate return true) of all child component.
By default, if there no shouldComponentUpdate method, it is considered that it has returned true. It does not matter whether you use immutable data or not - react does not know about it.
If you have immutable data you want avoid rerender, you should use shouldComponentUpdate. You can use pure-render-decorator, for example – it's check component state and props.
But if you change your state in componentWillReceiveProps you still get rerender because componentWillReceiveProps is called before shouldComponentUpdate.