Enzo
Enzo

Reputation: 318

Passing props to nested child component

Here's my structure :

Main.js (Parent)
MainContainer.js
|
|_ Article.js
       |
       |__ Comments.js

Now i want to set click handler on comment component (recursive component) and dispatch an action.

here's my code on comment.js

class Comment extends Component {
    deleteComment = (id) => {
        this.props.handleDelete(id)
    }
    render() {
        var comment = this.props.comment
        return (
            <div className={styles.commentsWrapper}>
                <ul>
                    <li>
                        <div className={styles.commentsName}>
                            <a onClick={() => this.deleteComment(comment.id)} className={styles.commentsNameRight}>
                            </a>
                        </div>
                        <p>{comment.body}</p>
                        {comment.children.length > 0 && comment.children.map(function(child) {
                            return <Comment comment={child} key={child.id}/>
                        })}

                    </li>
                </ul>
            </div>
        );
    }
}
export default Comment;

and Article.js :

 class Article extends Component {    

        handleDeleteComment = (id) => {
            this.props.deleteComment(id)
        }


        render() {
            return (
                <article className={styles.articleItem}>
                        {this.props.comments.map(item =>
                            <Comment handleDelete={this.handleDeleteComment} comment={item} key={item.id}/>)}
                </article>
            );
        }
    }


    export default Article;

And the Main.js

class Main extends Component {
    deleteComment = (id) => {
        this.props.deleteCommentRequest(id)
    }

    render() {
        return (
            <div className="">
                <Header />
                <section className="container">
                    <div>
                        {
                            !this.props.articles.loading && this.props.articles.articles? (
                                <div>
                                    {this.props.articles.articles.map(item =>
                                        <Article
                                        bodytext={item.selftext}
                                        key={item.id}
                                        comments={item.finalComments}
                                        deleteComment={this.deleteComment}
                                        />)}
                                </div>

                            ) : (
                                <div className={styles.loading}> <Spin /> </div>
                            )
                        }
                    </div>
                </section>
            </div>
        );
    }
}

export default Main;

so what i did here is: pass deleteComment as props from main to article and pass again handleDelete from article to comment.

not sure if it's a good way of doing this ?

Thanks in advance

Upvotes: 1

Views: 2490

Answers (2)

Sadeghbayan
Sadeghbayan

Reputation: 1163

you can use context API to have the props in the wrapper and easily accessible from child component.

there is a great tutorial from wesbos on youtube

class App extends Component {
  render() {
    return (
      <MyProvider>
        <div>
          <p>I am the app</p>
          <Family />
        </div>
      </MyProvider>
    );
  }
}


class MyProvider extends Component {
  state = {
    name: 'Wes',
    age: 100,
    cool: true
  }
  render() {
    return (
      <MyContext.Provider value={{
        state: this.state,
        growAYearOlder: () => this.setState({
          age: this.state.age + 1
        })
      }}>
        {this.props.children}
      </MyContext.Provider>
    )
  }
}

Upvotes: 1

Easwar
Easwar

Reputation: 5422

Nothing wrong with this pattern for 2 - 3 depth of components, as that is how data should flow from children to ancestors. But if your application is getting heavier with several layers, consider a different state management such as redux where a global state is maintained and any component can subscribe to it and dispatch actions. More on that here.

Alternatively you can also achieve the same with React Hooks with useContext where you can set the context and any child component can subscribe to it. Example:

const MyContext = React.createContext();

export default function App({ children }) {
  const [items, setItems] = React.useState([]);
  return (
    <MyContext.Provider value={{ items, setItems }}>
      {children}
    </MyContext.Provider>
  );
}

export { MyContext };

Now in any child at any level of depth as long as it is within App component's children, you can do this:

import {MyContext} from './filename';

function TodoItem() {
  const { items, setItems } = React.useContext(MyContext);
  return (
    <div onClick={() => setItems(1)}>

    </div>
  );
 }

Upvotes: 2

Related Questions