I am trying to get this componentFunction to re-render with the new data field on the state change that occurs changeValue and I don't know where I'm going wrong.
class Classname extends React.Component {
constructor() {
super();
this.state = {
value: "OriginalString",
};
}
changeValue = (newString) => {
this.setState({ value: newString });
this.forceUpdate();
};
componentFunction = () => {
return (
<div>
<component data={this.state.value} />
</div>
);
};
render() {
return (
<div>
<button
onClick={() => {
this.changeValue("updatedString");
}}
>
Update
</button>
<div className="control-section">
<DashboardLayoutComponent
id="dashboard_default"
columns={5}
cellSpacing={this.cellSpacing}
allowResizing={false}
resizeStop={this.onPanelResize.bind(this)}
>
<PanelsDirective>
<PanelDirective
sizeX={5}
sizeY={2}
row={0}
col={0}
content={this.componentFunction}
/>
</PanelsDirective>
</DashboardLayoutComponent>
</div>
</div>
);
}
}
ReactDOM.render(<Classname />, document.getElementById("root"));
<div id="root"></div>
<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>
Issue
The issue here is a stale enclosure of this.state.value in componentFunction.
Solution(s)
From what I can tell, the content prop of PanelDirective expects anything that returns, or resolves, to valid JSX (JSX attribute). A function callback to provide the content, a React component, or JSX literal all work.
Callback to reenclose updated state. Convert to a curried function that can enclose the current state when component is rendered. When attaching the callback you invoke the first function and pass the state value, the returned function is what PanelDirective will use when calling for the content value.
componentFunction = (data) => () => (
<div>
<component data={data} />
</div>
);
...
<PanelDirective
sizeX={5}
sizeY={2}
row={0}
col={0}
content={this.componentFunction(this.state.value)}
/>
React component. Convert componentFucntion to a React component and pass.
ComponentFunction = ({ data }) => (
<div>
<component data={data} />
</div>
);
...
<PanelDirective
sizeX={5}
sizeY={2}
row={0}
col={0}
content={<ComponentFunction data={this.state.value} />}
/>
JSX literal
<PanelDirective
sizeX={5}
sizeY={2}
row={0}
col={0}
content={
<div>
<component data={this.state.value} />
</div>
}
/>
Also, in case it wasn't obvious, you should remove the this.forceUpdate(); call in the changeValue handler. React state updates are sufficient in triggering the component to rerender.
try to pass in the value as param for the componentFunction, then each time the status value changed, the current component re-render, the trigger the function to re-render the child component using new state value.
class classname extends React.Component {
constructor() {
super();
this.state = {
value: "OriginalString",
};
}
changeValue = (newString) => {
this.setState({ value: newString });
this.forceUpdate();
}
componentFunction = (val) => {
return (
<div>
<component data={val} />
</div>
);
}
render() {
return (
<div>
<button onClick={() => { this.changeValue('updatedString') }}>Update</button>
<div className="control-section">
<DashboardLayoutComponent id="dashboard_default" columns={5} cellSpacing={this.cellSpacing} allowResizing={false} resizeStop={this.onPanelResize.bind(this)} >
<PanelsDirective>
<PanelDirective sizeX={5} sizeY={2} row={0} col={0} content={this.componentFunction(this.state.value)} />
</PanelsDirective>
</DashboardLayoutComponent>
</div>
</div>
);
}
}
Related
I'm trying to control inputs with state.
But I'm having a problem with this case which input keep losing it's focus when I hit the keyboard.
See picture below:
https://codesandbox.io/s/how-to-solve-this-7kwj6
export default class App extends React.Component {
constructor(props) {
super(props);
this.onBchange = this.onBchange.bind(this);
}
state = {
a: true,
b: "",
c: ""
};
onBchange(e) {
const thisClass = this;
return (async function() {
await thisClass.setState({ b: e.target.value });
console.log(thisClass.state.b);
})();
}
onCchange = e => {
this.setState({ c: e.target.value });
};
render() {
// this cause problem why?
const Test = ({ b, c, onBchange, onCchange }) => (
<Fragment>
<span>B: </span>
<input value={b} onChange={onBchange} />
<span>C: </span>
<input value={c} onChange={onCchange} />
</Fragment>
);
return (
<div className="App">
{this.state.a && (
<Test
b={this.state.b}
c={this.state.c}
onBchange={this.onBchange}
onCchange={this.onCchange}
/>
)}
</div>
);
}
}
Please let me know if you need more info about this.
Any ideas?
Your app is rerendering those elements on each change because each keystroke causes new props to be passed to <Test/> within your App's render method.
Notice that changing the return method in render to this stops the issue:
<div className="App">
<span>B: </span>
<input value={this.state.b} onChange={this.onBchange} />
<span>C: </span>
<input value={this.state.c} onChange={this.onCchange} />
{/* {this.state.a && (
<Test
b={this.state.b}
c={this.state.c}
onBchange={this.onBchange}
onCchange={this.onCchange}
/>
)} */}
</div>
i have created three components Aboutus,AboutusChild & GrandChild and now i want to pass grandchild state value in my grandparent component that is "Aboutus" component but without using intermediate component(AboutusChild), is it possible in react js without using redux state management library.
i dont' want to use redux right now until some data-communication concept are not clear.
class AboutUs extends Component {
constructor(props) {
super(props)`enter code here`
this.state = {
childState: false
}
}
myMehtod(value) {
this.setState({
childState: value
})
}
render() {
console.log('AboutUs', this.state.childState)
return (
<div>
<h1 className={`title ${this.state.childState ? 'on' : ''}`}>
About us {this.props.aboutusProp}
</h1>
<AboutUsChild />
</div>
)
}
};
class AboutUsChild extends Component {
myMehtod(value) {
this.setState({
childState: value
},
this.props.myMehtodProp(!this.state.childState)
)
}
render() {
console.log('AboutUsChild', this.state.childState)
return (
<div>
<h1 className={`title ${this.state.childState ? 'on' : ''}`}>About Us Child</h1>
<GrandChild>
without function
</GrandChild>
<h1>About Us Child</h1>
<GrandChild Method={true} myMehtodProp={this.myMehtod.bind(this)} />
</div>
)
}
};
class GrandChild extends Component {
constructor() {
super()
this.state = {
TitleClick: false
}
}
TitleClick() {
this.setState(
{
TitleClick: !this.state.TitleClick
},
this.props.myMehtodProp(!this.state.TitleClick)
)
}
render() {
console.log('GrandChild', this.state.TitleClick)
return (
<div>
{this.props.Method ?
<h1 onClick={this.TitleClick.bind(this)} className={`title ${this.state.TitleClick ? 'on' : ''}`}>Grand Child</h1>
: null}
<h1>{this.props.children}</h1>
</div>
)
}
};
There's really no way to pass child state up without passing it to some callback. But frankly speaking this does not seem like a good design choice to me. You should always have common state on top of all components consuming that state. What you can do, is to pass stuff as children:
class SomeComponent extends React.Component {
...
render() {
const { value } = this.state;
return (
<Child value={value}>
<GrandChild value={value} onChange={this.handleValueChange} />
</Child>
);
}
}
const Child = ({ value, children }) => (
<div>
<h1 className={`title ${value ? 'on' : ''}`}>About Us Child</h1>
{children}
</div>
)
const GrandChild = ({ value, onChange }) => (
<div>
<h1 onClick={onChange} className={`title ${value ? 'on' : ''}`}>Grand Child</h1>
</div>
);
This way you got control from parent component of everything. If this is not the way, because you are already passing children, and for some reason you want to keep it this way, you can pass "render" prop:
// JSX in <SomeComponent /> render function:
<Child
value={value}
grandChild=(<GrandChild value={value} onChange={this.handleValueChange} />)
>
Some other children
</Child>
...
const Child = ({ value, grandChild, children }) => (
<div>
<h1 className={`title ${value ? 'on' : ''}`}>About Us Child</h1>
{grandChild}
{children}
</div>
)
If you want to be more fancy and there will more than few levels of nesting, you can always use context (highly recommend reading docs before using):
const someContext = React.createContext({ value: true, onChange: () => {} });
class SomeComponent extends React.Component {
...
render() {
const { value } = this.state;
return (
<someContext.Provider value={{ value: value, onChange: this.handleValueChange }}>
<Children>
</someContext.Provider>
);
}
}
...
const SomeDeeplyNestedChildren = () => (
<someContext.Consumer>
{({ value, onChange }) => (
<h1 onClick={onChange}>{value}</h1>
)}
</someContext.Consumer>
)
I would pick first two, if your structure is not that complex, but if you are passing props deeply, use context.
The only way to do something of this sort without external library would be leveraging React's Context API, although bare in mind that it is not nearly as robust as redux or mobX.
I am new to React and need some help to my specific situation. I have a top-level app.js where I render
export default class Page extends React.Component {
constructor(props) {
super(props);
this.state = {
currentGuess: '',
historicGuess: '',
result: ''
};
}
handleCurrentGuess(event) {
console.log(event)
this.setState({currentGuess: event.target.value})
}
handleSend() {
console.log(this.state.currentGuess)
}
render() {
return (
<div className="wrapper">
<Header />
<Logic handleCurrentGuess={this.handleCurrentGuess}/>
<Result />
</div>
)
}
}
The component has to be stateful, and I enter the currentGuess value into state.
The <Logic /> looks like this:
export default function Logic(props) {
console.log(props)
return (
<div className="logic">
<form>
<input type="text" onChange={props.handleCurrentGuess}/>
<button onClick={(e) => {
e.preventDefault()
props.handleSend
}}>Send</button>
</form>
</div>
)
}
The issue now is that I cannot find documentation on how to pass both pass the function on to the AND get returned a value from the input. Most docs show onChange via the input directly, but I want to fetch the value ONLY when someone clicks on the submit button (or hits enter). So,
how do I pass the correct function to the child, and how do I get the text value back on button press within the Logic component?
If you want to console.log the state right now (for testing purposes obviously) here is the two problems with your code.
First, you are not passing your handleSend function as a prop to Logic component.
Second, on your button, you are not invoking this handleSend function in your onClick handler.
Here is a working example.
const Logic = props => (
<div className="logic">
<form>
<input type="text" onChange={props.handleCurrentGuess} />
<button onClick={props.handleSend}>Send</button>
</form>
</div>
);
class Page extends React.Component {
state = {
currentGuess: '',
historicGuess: '',
result: ''
};
handleCurrentGuess = event =>
this.setState({ currentGuess: event.target.value })
handleSend = (e) => {
e.preventDefault();
console.log(this.state.currentGuess)
}
render() {
return (
<div className="wrapper">
<Logic
handleCurrentGuess={this.handleCurrentGuess}
handleSend={this.handleSend} />
</div>
)
}
}
ReactDOM.render(<Page />, document.getElementById("root"));
<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>
<div id="root"></div>
I slightly changed the code. Use some arrow functions so no need to .bind them, remove the unnecessary constructor, use class-fields, etc. I also used the function reference for onClick in the button.
how to pass an argument in props using functional component, here I had given my worked example code,
Let me explain, My click event will trigger from PopUpHandle when I click on the PopUpHandle I need to get the value from ContentSection component. ContentSection will be the listing, when clicking on each listing want to get the value of the current clicked list. I tried with this code my console printed undefined but I don't know how to handle with functional component.
class mainComponent extends Component {
constructor(props) {
super(props);
this.popTrigger = this.popTrigger.bind(this);
}
popTrigger(data){
console.log(data);
}
render(){
return(
<Popup popTrigger={this.popTrigger} />
)
}
}
export default mainComponent;
Popup component
const PopUpHandle = ({ popTrigger, value}) => <li onClick={popTrigger.bind(this, value)} />;
const ContentSection =({popTrigger, value}) =>(
<div>
{value === 'TEST1' && (
<div>
<PopUpHandle popTrigger={popTrigger} value={value} />
</div>
</div>
)}
{value === 'TEST2' && (
<div>
<PopUpHandle popTrigger={popTrigger} value={value} />
</div>
</div>
)}
</div>
)
const ContentList = (({ items, popTrigger}) => (
<div>
{items.map((value, index) => (
<ContentSection
key={`item-${index}`}
popTrigger={popTrigger}
index={index}
value={value}
/>
))}
</div>
)
);
class example extends Component {
constructor(props) {
super(props);
this.state = {
items: ['TEST1', 'TEST2', 'TEST3', 'TEST4'],
};
this.popTrigger = this.popTrigger.bind(this);
}
popTrigger(){
this.props.popTrigger()
}
render(){
return(
<ContentList popTrigger={this.popTrigger} items={this.state.items} />
)
}
}
export default example;
popTrigger(data){
console.log(data);
}
You didn't pass the data while calling this.props.popTrigger(). In javascript if you didn't pass the arguments, it will consider it as undefined.
The ContentSection component is not passed a value prop and hence its not passed on to the PopUpHandle component. Pass it like
render(){
return(
<ContentSection popTrigger={this.popTrigger} value={"test1"} />
)
}
I set a material-ui/TextField in my user-defined component. The user-defined component is named LabelTextField. I render several LabelTextField in my user-defined component which is named TextList. My question is how to get the values of textField in the TextList component.
A button is next to the TextList component in the View component. I will save all the TextField values when someone clicks the button.
I will post a network request in the TextList component to save the value to the backend.
I am using Redux. Does every material-ui/TextField should dispatch the value in the onChange callback function?
The onChange is at the bottom of this website:
http://www.material-ui.com/#/components/text-field
My central code:
LabelTextField:
textChangeFun = (value) => {
}
render() {
return (
<div>
<div style={{fontSize:0}}>
<div style={inlineStyle}>
<FlatButton disableTouchRipple={true} disabled={true} label={this.props.labelValue} />
</div>
<div style={inlineStyle}>
<TextField
hintText={this.props.textValue}
/>
</div>
</div>
</div>
);
}
TextList:
render(){
return (
<div>
{demoData.map((item,id) =>
<LabelTextField key={id} labelValue={item.label} textValue={item.text} ></LabelTextField>
)}
</div>
)
}
You need to give LabelTextField a handler for the change event.
class LabelTextField extends React.Component {
onChange(e) {
this.props.onChange({ id: this.props.id, value: e.currentTarget.value })
}
render() {
return (
<div>
<div style={{fontSize:0}}>
<div style={inlineStyle}>
<FlatButton disableTouchRipple={true} disabled={true} label={this.props.labelValue} />
</div>
<div style={inlineStyle}>
<TextField
hintText={this.props.textValue}
onChange={this.onChange.bind(this)}
/>
</div>
</div>
</div>
);
}
}
class TextList extends React.Component {
constructor() {
super();
this.state.textFields = {}; // TODO: get initial state from demoData
this.onTextFieldChange = this.onTextFieldChange.bind(this);
}
onTextFieldChange = ({ id, value }) {
const { textFields } = this.state;
textFields[id] = value;
this.setState({ textFields });
}
render(){
return (
<div>
{demoData.map((item,id) =>
<LabelTextField key={id} labelValue={item.label} textValue={item.text} onChange={this.onTextFieldChange} ></LabelTextField>
)}
</div>
)
}
}
This way any time a textField changes, it causes the onTextFieldChange handler to be called and the state of TextList to update.
If you have a more complicated situation, you might consider using redux or even http://redux-form.com/6.5.0/