Child Component is not updating after Parent Component passes it new props - javascript

When I get userInput from onChange() and try to pass that to the child Component It is not updating rather holding on to the initial value.
I'm trying to pass the string from input field to child component called Tensor-flow Toxic Model, however the state of TensorFlowToxidModel does not change after it is initially set. So I cant run the moddl.
class TensorFlowToxicModel extends React.Component<{}, ToxicityModelProp> {
constructor(props: userInput) {
super(props);
this.state = {
modelObjectArray: [],
userSentence: props.userSentence,
};
}
componentDidUpdate(){
console.log("This is from TensorFlowToxicModel Compononent")
console.log("This is the sentence ", this.state.userSentence )
}
renderThePost = () => {
let output = cleanMlOutput(this.state.userSentence)
return output
};
render() {
return (
<div>
<p>This is a Checker Does this even work</p>
</div>
);
}
}
class InputField extends React.Component<{}, userInput> {
constructor(prop: inputFromField) {
super(prop);
this.state = {
userSentence: "",
};
}
handleChange = (event: React.FormEvent<HTMLInputElement>): void => {
let userInputData: string = event.currentTarget.value;
//console.log(event.currentTarget.value);
this.setState({
userSentence: userInputData,
});
};
render() {
const userSentence = {
userSentence:this.state.userSentence
}
//Instead of updating TensorFlowToxicModel Each time from inside its own compnoent
//Call it here each time user types something
return (
<div>
<input id="inputField" onChange={this.handleChange} />
<h4>{this.state.userSentence}</h4>
<TensorFlowToxicModel {...userSentence}/>
</div>
);
}
}
the Types
type modelObject = { label: string; resultMatch: boolean; resultProbablity: number; };
type ToxicityModelProp = { userSentence: string; modelObjectArray : modelObject[] }

You're misplaced the prop types ToxicityModelProp. It should be on first. Read this docs for information about component props,state types
type ToxicityModelProp = { userSentence: string }
type ToxicityModelState = { modelObjectArray: [] }
class TensorFlowToxicModel extends React.Component<ToxicityModelProp, ToxicityModelState> {
constructor(props: userInput) {
super(props);
this.state = {
modelObjectArray: []
};
}
renderThePost = () => {
let output = cleanMlOutput(this.props.userSentence)
return output
};
render() {
return (
<div>
<p>Sentence is: { this.props.userSentence }</p>
</div>
);
}
}
I have made some changes on your code and update here. Check it out

Related

How to get value from this.state. Property of undefined

I'm trying to pass value from one component to another. First one looks like this:
class ListStation extends Component {
constructor(props) {
super(props)
this.state = {
stations: []
}
this.editStation = this.editStation.bind(this);
}
editStation(id) {
this.props.history.push(`/add-station/${id}`);
}
componentDidMount() {
StationService.getStations().then((res) => {
this.setState({ stations: res.data });
})
}
}
render() {
return (
<div>
<tbody>
{this.state.stations.map(
station =>
<tr key={station.id}>
<td>{station.city}</td>
<td>{station.name}</td>
<td>
<button onClick={() => this.editStation(station.id)} className="btn btn-info">Modify</button>
...
</div>
</div>
);
}
}
export default ListStation;
And another looks like this:
import React, { Component } from 'react';
import StationService from '../services/StationService';
class CreateStationComponent extends Component {
constructor(props) {
super(props)
this.state = {
station: {
id: this.props.match.params.id,
city: '',
name: '',
trains: [
{
number: '',
numberOfCarriages: ''
}
]
}
}
this.changeCityHandles = this.changeCityHandles.bind(this);
this.changeNameHandles = this.changeNameHandles.bind(this);
this.saveStation = this.saveStation.bind(this);
}
componentDidMount() {
if (this.state.station[0].id === '_add') {
return;
} else {
StationService.getStationById(this.state.id).then((res) => {
let station = res.data;
this.setState({ name: station[0].name, city: station[0].city })
});
}
console.log(this.state.station.city + 'dfddddd');
}
But when I try to pass value from one component to another I get error: Property of undefined. The response I get from API looks like this:
I'm trying to edit values based on the id taken from the first component but it seems to fail.
if (this.state.station[0].id === '_add') {
return;
}
Have a look at this if statement from your codebase I think you should remove [0] after this.state.station ... this is because station is an object not an Array
Change it to if (this.state.station.id === '_add') {

Perform validation before every render

I'm working on this component and I want to validate its fields before every render. If they are not valid I want to disable a button in the parent.
Here is what I've got thus far:
export default function Input(props) {
const [inputs] = useState(props.inputs);
const didChangeRef = useRef([]);
useEffect(() => {
if (!_.isEqual(didMountRef.current, props.inputs)) {
validateInput(input);
didChangeRef.current = props.inputs;
}
});
const validateInput = input => {
const errors = useValidation(input);
if(Object.keys(errors).length !== 0) {
props.setIsValid(false);
}
}
return (
<input
onChange={e=> props.setProperty(e)}>
</input>
<input
onChange={e=> props.setProperty(e)}>
</input>
)
}
If an input is changed, it sets a property in the parent and this component is re-rendered. Inputs is an array of objects and I wish to validate it's contents on each render (or componentDidMount). I either manage to get it to loop infinitely or run the validation only once.
I appreciate your help.
P.S.:
I tried another approach as well, but it still ends up looping infinately:
export default function Input(props) {
const didMountRef = useRef(true);
useLayoutEffect(() => {
if (didMountRef.current) {
didMountRef.current = false;
return;
}
validate(input);
});
const validate = input => {
// validation...
}
}
Here is the parent component:
class CreateShoppingItem extends React.Component {
constructor(props) {
super(props);
this.state = {
storage: {},
isValid: true,
};
}
setIsValid = (isValid) => {
this.setState({ isValid });
};
render() {
return (
<div>
<Input setIsValid={this.setIsValid} inputs={this.storage.inputs} />
<Button disable={!isValid}></Button>
</div>
);
}
}

Can a child method have change handler in React?

I was wondering why the child component with the changed value is not getting rendered here.
Isn't it a good idea to have a child handle its own changes or better to have the controller in the parent?
class App extends React.Component {
constructor() {
super();
this.state = {
todos: todosData
};
}
render() {
const todoItems = this.state.todos.map(item => (
<TodoItem key={item.id} item={item} />
));
return <div className="todo-list">{todoItems}</div>;
}
}
This is the Child TodoItem
class TodoItem extends React.Component {
constructor(props) {
super(props);
this.state = {
isComp: {}
};
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
let tempObj = this.state.isComp;
tempObj.completed = !this.state.isComp.completed;
this.setState = { isComp: tempObj };
console.log(this.state.isComp);
}
render() {
this.state.isComp = this.props.item;
console.log(this.state.isComp);
return (
<div className="todo-item">
<input type="checkbox" checked={this.state.isComp.completed} />
<p>{this.props.item.text}</p>
</div>
);
}
}
As you can see the state is changed with handleChange() but this does not fire the render. I am also not too sure if another object can be assigned to an object of the state (let tempObj = thi.state.isComp).
The functionality I am trying to achieve is check and uncheck a box and render accordingly.
What is this?
this.setState = { isComp: tempObj };
I think it should be
this.setState({ isComp: tempObj });

How can I Set State of a Value that is inside some other Function

I am Trying to Create a React App That Detects Age of Pictures Using Clarifai API .
I am Able to Console.Log Detected Age but I Want To Display The Age on My Webpage . Help me With Setting The AgeDectect State so I Can Use it on my Webpage
//Value Displayed On Console
//39
​
//App.js Code That Console.Logs Age
class App extends Component {
constructor(){
super();
this.state = {
input : '',
imgURL : '',
AgeDetect : ''
}
}
onInputChange = (event) => {
this.setState({input : event.target.value});
}
onClickEvent = () => {
this.setState({imgURL : this.state.input})
app.models.predict(Clarifai.DEMOGRAPHICS_MODEL ,
this.state.input).then(
function(response) {
const A =response.outputs[0].data.regions[0].
data.face.age_appearance.concepts[0].name
//This Line of Code Displays Age on Console
console.log(A);
this.setState({AgeDetect : A});
},
//Having Problem SettingState ,this.state.AgeDetect isnt
//doing anything
render(){
return (<AgeDetection AgeDetect={this.state.AgeDetect}/>
)
}
//AgeDetection.js file
import React from 'react' ;
const AgeDetection = ({AgeDetect}) => {
return(
<div>
{AgeDetect}
</div>
);
}
export default AgeDetection;
Sort your array that is returned by the value and set the first object or the whole array to your state and then you can use it in your app very easily. Use an arrow function inside your predict then block to bind to the class.
class App extends Component {
constructor() {
super();
this.state = {
input: '',
imgURL: '',
AgeDetect: ''
};
}
onInputChange = event => {
this.setState({ input: event.target.value });
};
onClickEvent = () => {
this.setState({ imgURL: this.state.input });
app.models.predict(Clarifai.DEMOGRAPHICS_MODEL, this.state.input).then(
response => {
const A =
response.outputs[0].data.regions[0].data.face.age_appearance
.concepts[0].name;
this.setState({ AgeDetect: A });
},
function(err) {
// there was an error
}
);
};
render() {
console.log(this.state);
return (
<div className='App'>
<Navigation />
<Logo />
<ImageLinkForm
onInputChange={this.onInputChange}
onClickEvent={this.onClickEvent}
/>
<FaceRecognition imgURL={this.state.imgURL} />
<AgeDetection AgeDetect={this.state.AgeDetect} />
</div>
);
}
}
export default App;

Load data before rendering child elements React

I am trying to generate a list of selector options based on external JSON data. The code here is mostly good, except that part of it is being called before the data is loading resulting in no children being appended. I am sure there is a way to implement this but I'm not sure what that way is for my particular situation.
Here is the code:
class PokedexSelector extends Component {
constructor(props) {
super(props);
this.state = {value: "National", pokedexes: []};
this.generatePokedexList();
this.handleChange = this.handleChange.bind(this);
this.generatePokedexList = this.generatePokedexList.bind(this);
this.pokedexList = this.pokedexList.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
generatePokedexList() {
const pokedexes = [];
fetch("https://pokeapi.co/api/v2/pokedex/")
.then(response => response.json())
.then(myJson => {
let results = myJson["results"];
results.forEach(function(pokedex) {
let pokedexName = pokedex["name"];
let pokedexLink = "https://pokeapi.co/api/v2/pokedex/" + pokedexName;
let pokedexDisplayName = capitalize(pokedexName.replace('-',' '));
pokedexes.push(
{
name: pokedexName,
displayName: pokedexDisplayName,
link: pokedexLink
}
);
});
this.state.pokedexes = pokedexes;
console.log(this.state.pokedexes)
})
}
pokedexList() {
if (this.state.pokedexes.length > 0) {
console.log("listing")
return (
this.state.pokedexes.map(pokedex => (
<option>{pokedex.displayName}</option>
))
)
}
}
render() {
return (
<select id="pokedex-selector" value={this.state.value} onChange={this.handleChange}>
{this.pokedexList()}
</select>
)
}
}
export default PokedexSelector;
I tried using componentDidMount() as below, but I'm not sure how to specifically target one component for changes in this case (the <select> element).
componentDidMount() {
{this.pokedexList()}
}
Any ideas? Thanks!
You should make your fetch calls before the render method is triggered, ideally in componentDidMount and store the response in the state. The component will re-render only when the state or props changes.
state should be updated via this.setState() method and should not be directly mutated using this.state.
In your case, since you're trying to mutate the state directly using this.state the component will not re-render. You should replace it with this.setState().
Try this code
class PokedexSelector extends Component {
constructor(props) {
super(props);
this.state = {value: "National", pokedexes: []};
this.handleChange = this.handleChange.bind(this);
this.generatePokedexList = this.generatePokedexList.bind(this);
this.pokedexList = this.pokedexList.bind(this);
}
componentDidMount() {
this.generatePokedexList();
}
handleChange(event) {
this.setState({value: event.target.value});
}
generatePokedexList() {
const pokedexes = [];
fetch("https://pokeapi.co/api/v2/pokedex/")
.then(response => response.json())
.then(myJson => {
let results = myJson["results"];
results.forEach(function(pokedex) {
let pokedexName = pokedex["name"];
let pokedexLink = "https://pokeapi.co/api/v2/pokedex/" + pokedexName;
let pokedexDisplayName = capitalize(pokedexName.replace('-',' '));
pokedexes.push(
{
name: pokedexName,
displayName: pokedexDisplayName,
link: pokedexLink
}
);
});
this.setState({pokedexes: pokedexes}); // use setState()
})
}
pokedexList() {
if (this.state.pokedexes.length > 0) {
console.log("listing")
return (
this.state.pokedexes.map(pokedex => (
<option>{pokedex.displayName}</option>
))
)
}
}
render() {
return (
<select id="pokedex-selector" value={this.state.value} onChange={this.handleChange}>
{this.pokedexList()}
</select>
)
}
}
export default PokedexSelector;
It should be this.setState and not this.state.pokedexes = pokedexes. Do not mutate state directly.
this.setState({
pokedexes
})

Categories