Tammy
Tammy

Reputation: 1132

How to pass `props` data from parent to child on react router

I want to pass my props data from parent to child when it will route to new path. I tried some https://github.com/ReactTraining/react-router/issues/4105 but not actually worked when i passed it through {...props}.

any help would be greatful.

//App.js

class App extends Component{
  constructor(props){
    super(props);
  }

  render(){
    return (
      <div className="App">
        <div className="navbar">
          <h2 className="center">Tiny Book Library</h2>
        </div>
        <Switch>
          <Route exact path="/" component={PostBook}/>
          <Route exact path="/abc" render={props => <AllBook someProp="2" {...props} />} />
        </Switch>

      </div>
    );
  }
}

//Allbook.js

class AllBook extends Component {
    constructor(props){
        super(props);
      }
    render(){
        return(
            <div>
                {Object.keys(this.props.posts).length !== 0 ?  <h1 className="post-heading">All books</h1> : ""}  {/*To check if array is empty or not*/}

                {/*Arrow function to map each added object*/}
                {this.props.posts.map((post) =>(

                    <div key={post.id}>

                        {post.editing ? <EditComponent post={post} key={post.id}/> :
                            <Post key={post.id} post={post}/>}
                    </div>
                ))}
            </div>
        );
    }
}

const mapStateToProps = (state) => {
    return{
        posts: state
    }
}
export default connect(mapStateToProps)(AllBook);

//reducer

const postReducer = (state = [], action) => {
    switch(action.type){
        case 'ADD_BOOK':
            return state.concat([action.data]);
        case 'DELETE_BOOK':
            return state.filter((post) => post.id !== action.id);
        case 'EDIT_BOOK':
            return state.map((post)=>post.id === action.id ? {...post, editing:!post.editing} : post)
        case 'UPDATE':
            return state.map((post)=>{
                if(post.id === action.id){
                    return{
                        ...post,
                        title: action.data.newTitle,
                        number:action.data.newNumber,
                        author:action.data.newAuthor,
                        description:action.data.newDescription,
                        editing: !post.editing
                    }
                } 
                else return post;
            })
        default:
            return state;
    }
}
export default postReducer;

Upvotes: 0

Views: 2987

Answers (3)

Sultan H.
Sultan H.

Reputation: 2938

UPDATE #1: Adding a Link for the sake of a Correct Page Transition:

  • First: import Link component at the beginning of your App.js:

import { Link } from 'react-router-dom'

  • Second: Add Link components to route between both pages:
class App extends Component{
  constructor(props){
    super(props);
  }

  render(){
    return (
      <div className="App">
        <div className="navbar">
          <h2 className="center">Tiny Book Library</h2>
          <Link to="/">Post A Book</Link>
          <Link to="/abc">All Books</Link>
        </div>
        <Switch>
          <Route exact path="/" component={PostBook}/>
          <Route exact path="/abc" render={props => <AllBook someProp="2" {...props} />} />
        </Switch>

      </div>
    );
  }
}

There is probably nothing wrong with the code above, the cause of this behavior is changing the route manually from the browser.

Which causes the problem.

Explaining further:

  • You post the data from the form in PostBook.
  • The data is stored in the reducer.
  • You change the url manually from the browser, you lose all the data you have submitted to the reducer, this is not an error, nor an expected behavior, because doing that will request entirely new app for you, thus, ZERO DATA.

Please read about Link, to change the url properly so you can test your code whether it works or not.

Upvotes: 2

Adolfo Onrubia
Adolfo Onrubia

Reputation: 1831

Not sure if would be helpfull. Subscribe Allbook to posts, in your case looks like your entire redux store is just posts, or at least you are passing all redux state to posts.

class AllBook extends Component {
    constructor(props){
        super(props);
      }
    render(){
        return(
            <div>
                {Object.keys(this.props.posts).length !== 0 ?  <h1 className="post-heading">All books</h1> : ""}  {/*To check if array is empty or not*/}

                {/*Arrow function to map each added object*/}
                {this.props.posts.map((post) =>(

                    <div key={post.id}>

                        {post.editing ? <EditComponent post={post} key={post.id}/> :
                            <Post key={post.id} post={post}/>}
                    </div>
                ))}
            </div>
        );
    }
}

// (state) => { return { posts: state.posts } }; Should also work.
const mapStateToProps = ({ posts }) => ({ posts });

export default connect(mapStateToProps)(AllBook);

Upvotes: 1

Gershon Papi
Gershon Papi

Reputation: 5126

As mentioned in the react-router docs, the parameters in the render function prop are the router props: i.e. the props that the Route component would normally get: history, location and more.

You don't want that, you want to pass your own/parent props: \ App.js

class App extends Component{
  constructor(props){
    super(props);
  }

  render(){
    const myProps = this.props;

    return (
      <div className="App">
        <div className="navbar">
          <h2 className="center">Tiny Book Library</h2>
        </div>
        <Switch>
          <Route exact path="/" component={PostBook}/>
          <Route exact path="/abc" render={() => <AllBook someProp="2" {...myProps} />} />
        </Switch>

      </div>
    );
  }
}

Upvotes: 2

Related Questions