Redux: passing information to/from window child - javascript

Essentially I am trying to create an app where it has a note-pad feature that opens up a window child and passes some information from the parent (which holds the redux state) to it.
However, I am having trouble on how to send the information from the child to the parent, specifically dealing with dispatching action.
I was able to figure it out on passing from parent to child as so without using Redux:
Parent Window
class NavBar extends React.Component {
constructor() {
super()
this.handleNotesMenu = this.handleNotesMenu.bind(this)
}
handleNotesMenu() {
window.id = this.props.id
window.userName = this.props.userName
window.currentReduxState = store.getState()
const notePad = window.open('NotePad', 'notes', 'toolbar=0,status=0,width=715,height=325')
}
Child Window
export class NotePad extends React.Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
this.state = {
notes: window.opener.state.getIn(['plan', 'notes'])
}
}
handleChange(tabID) {
return e => {
const state = {}
state[tabID] = e.target.value
this.setState(state)
}
}
render() {
return (
<textarea
id="saveArea"
value={this.state.notes}
onChange={this.handleChange('notes')}
name="textarea"
/>
)
}
}
I thought out about that adding action dispatcher to the child was hard, so I was thinking somehow incorporate with sessionStorage. But then I got stumped on how the parent window is able to listen to listenStorage on the fly.
Any thoughts? What would be the best practice when it comes to dealing with window child in React/Redux?

Send a method as prop which will take the returning data as argument from child component and call this method in your childcomponent with that data...like this....
In parent component.....
someMethod(data){
// do something here with data
}
In your render method pass this method to child component as...
<ChildComponent someMethod={this.someMethod} />
Now in your child component call that method like this...
this.props.someMethod(someData);
And that's it your are done...
You have passed the data your parent component without dispatch ... In that someMethod() you can do whatever you wanna do with that data

Related

How to set variable from parent inside child's componentDidMount react?

I am trying fetch the information from Api request in child component. The problem is that I have faced accessing parent's props. More precisely how to get parent's props and set it inside componentDidMount()?
Parent component
class Parent extends Component {
constructor(){
super()
}
...
<Child id={id}/>
...
export default Parent;
Child component
class Child extends Component {
constructor(){
super()
this.state = {
id:'',
}
}
// I need somehow set parent's "id" inside the url
componentDidMount() {
const url = `https://api.../${id}?api_key=${apiKey}`;
axios.get( url )
...
};
render(){
const { id } = this.props;
console.log('Child id ' + id) // here I see all ids
return(
<div className="item" key={id}>
<p>{id}</p> // here as well
</div>
)
}
}
Child.propTypes = {
item: PropTypes.object
}
export default Child;
Maybe I am looking for in the wrong place and I need just change logic.
I will be grateful for any advice
To access props from anywhere in your Child component you need to pass props to your constructor, then you just access it using this.props.
This should work:
class Child extends Component {
constructor(props){
super(props)
this.state = {},
}
componentDidMount() {
const id = this.props.id
const url = "https://api.../$" + id + "?api_key=${apiKey}";
axios.get( url )
...
};
}
If you have a constructor in a component the props should always be passed to the constructor and also to React component using super()
constructor(props){
super(props)
}
In your case if you have to use your parents props you should also pass the parents props to child also and with same syntax in constructor you can use props that you passed in anywhere of the child component and you can set that props in componentDidMount as well

React props value is undefined

This is my parent code:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
tags: [],
};
}
componentDidMount() {
this.getTags();
}
getTags() {
//method gets tags from the backend
}
render() {
return <Child tags={this.state.tags} />;
}
}
And this is basically my child component:
export default class Child extends Component {
constructor(props) {
super(props);
this.state = {
tags: props.tags,
};
}
componentWillReceiveProps(nextProps) {
this.setState({
tags: nextProps.tags,
});
}
}
But when I console log tags somewhere in the Child component, it is undefined. Maybe it is undefined because the child component gets rendered before the parent component calls the method getTags? Or is there any other problem with this code? And how can I avoid this problem that tags are undefined in the child component?
Cheers
To avoid your problem, you shouldn't be rendering your Child component until the this.state.tags has any useful values.
Here is how you can do it and also show a "Loading..." text, so the user isn't worried the page is broken.
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
tags: [],
};
}
componentDidMount() {
this.getTags();
}
getTags() {
//method gets tags from the backend
}
render() {
return this.state.tags.length ? (
'Loading...'
) : (
<Child tags={this.state.tags} />
);
}
}
Your child component will definitely get rendered with the empty 'tags' array as a prop. Then, when getTags() returns the data, the newly populated tags array will be passed to the child as a prop, forcing the child to get re-rendered with the new data.
It should be the empty array though, not "undefined". You might check your getTags() method and the API you are calling to make sure you aren't getting "undefined" from there.
componentWillReceiveProps is legacy and should not be used. See the following link in the React docs for details: https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
That documentation will walk you through what to do if you need to perform side effects as a result of changing props.
Right now the only thing is componentWillReceiveProps is to set local state to the props, which is totally superfluous. Is there something else you are needing to do there?

State value not updating reactjs

class RaisablePaper extends Component {
constructor(props) {
super();
this.state = {
state1: "state1",
openNow: props.boxOpen,
};
}
}
I am trying to send value to this class by doing <RaisablePaper boxOpen={this.state.dOpen}/>. But whenever the dOpen gets changed it does not seem to update the openNow. Help would very much appreciated.
You are setting the state before mounting the component in the constructor, which will not be fired again when the props change. For that you can use React's componentWillReceiveProps, which will be called when new props are sent to the component.
class RaisablePaper extends Component {
constructor(props) {
super();
this.state = {
state1: "state1",
openNow: props.boxOpen
};
}
componentWillReceiveProps(props) {
this.setState({
openNow: props.boxOpen
});
}
}
It would be simpler to use the props directly instead of worrying about syncing it to your state. It's a good idea in general to rely on props as much as possible, and only involve state when absolutely necessary.
But Fabian Schultz is absolutely right -- your constructor only runs once, before the component is mounted, so you'll never receive the subsequent updates if the component is relying on state which is initialized during construction.
I'm just imagining how you're using the boxOpen state to show an example; you can follow the same general idea with whatever your render method is doing.
class RaisablePaper extends Component {
render() {
return (
<div className={this.props.boxOpen ? 'is-open' : ''}>
Here's some content...
</div>
);
}
}

Letting a child know that it should update its state in React

I'm trying to let a child Component know that it should update its state after a prop change in the parent.
There is no state that needs to be shared between the two. The only thing that needs to happen is that the parent should somehow let the child know that it needs to update its state (literally call setState by itself with the info it already has).
So far I can only figure out to do in the "React"-way through the componentWillReceiveProps and sending some arbitrary props, like a number, to let the child know that it should call the function to set the state.
Another way would be to use signals to let the child know, but this seems a bit over the top for this situation.
So in summary:
The parent needs to let the child know that it should call a function
The function will update the state (setState) of the child
There is no need for the child to receive any information from the parent
Can anyone help me figure out the best way to do this?
As you can see in the snippet, this is more or less the situation. I would like to know the best way to have the Child component call the _updateState function when the Parents props have changed (does not happen in the snippet right now).
//Imagine this is the redux-container that passes the store state to the parent.
class ParentWrapper extends React.Component {
constructor(){
super();
this.state = {status: 'normal'};
}
//This would be an action to the reducer that would update the store state
_updateStatus(){
this.setState({status: 'updated'});
}
render(){
return (
<div>
<button onClick={this._updateStatus.bind(this)}>Click me</button>
<Parent status={this.state.status} />
</div>
);
}
}
class Parent extends React.Component {
render(){
return (
<div>
<Child />
</div>
);
}
}
Parent.propTypes = {
status: React.PropTypes.string
};
Parent.defaultProps = {
status: 'normal'
};
class Child extends React.Component {
constructor(){
super();
this.state = { test: 1 };
}
_updateState(){
this.setState({test: this.state.test + 1});
}
render(){
return (
<div>Child: {this.state.test}</div>
);
}
}
ReactDOM.render(<ParentWrapper />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>
<div id="container"></div>
EDIT: added snippet.
You can use refs to access all the methods under the child component.
See the following fiddle
https://jsfiddle.net/pranesh_ravi/412j5ucw/
Here using refs, I'm calling a function inside the child which will change the state of the child component.

ReactJS: Accessing Child Final State

This may seem as a bit of a redundant question but I'm trying to access the final state of a child in React, after it has updated. I've been looking into the React LifeCycle docs (I think that might be the issue, but not sure), searched high and low, and can't quite figure it out.
I've got a component which needs to access the (final) value of the state of a child, once that child has done some updating (AJAX request which then does a few this.setStates).
So far, I'm able to access the entire state of that child, accessing through a ref (Inside componentDidMount), but when I try to access a specific value of said state, it returns null or undefined.
Here's some example code to explain (I'll try to spare you as much useless code as possible):
class Layout extends Component {
constructor(props) {
super(props);
}
componentDidMount(){
// This gives me the updated State where pageTitle = "Whatever"
console.log(this.refs.child1);
// However this gives me the initial State where pageTitle = null
console.log(this.refs.child1.state.pageTitle);
}
render(){
return (<div>
{React.cloneElement(
this.props.children,
{ref: 'child1'}
)}
</div>);
}
}
And here's the child component for reference (note: i'm using axios for my ajax requests):
export class ChildComponent extends Component {
constructor(props) {
super(props);
this.state = {
resultData: result,
pageTitle: null
}
}
componentDidMount(){
this.serverRequest = axios.get(apiUrl)
.then(function(result){
this.setState({
resultData: result,
pageTitle: result.pageTitle
});
}.bind(this))
}
render(){
return(<div>
{use of different this.state.resultData values works fine here}
</div>)
}
}
Appreciate any help that comes this way
To use a callback, add this code to the parent element:
handleAsyncDone(data) {
// Do whatever it is people do with data
}
And then pass that function to the child component, and in the childcomponent, add
this.props.handleAsyncDone(this.state);
Which will pass the child state back up to the parent.

Categories

Resources