如何使用从子组件传递给组件的反应变量更新 redux 状态

Posted

技术标签:

【中文标题】如何使用从子组件传递给组件的反应变量更新 redux 状态【英文标题】:How to update redux state using a react variable passed up to the component from a child 【发布时间】:2020-01-26 03:59:54 【问题描述】:

在表单提交回调之后,我尝试使用从子组件传递给该组件的变量来更新组件中的 Redux 状态。该表单提交用户评论,我想将其存储在我的 redux 状态中。我不确定如何将此变量发送到 redux 链中,以便我可以在我的动作创建器中使用它。我想将handleCommentSubmit 中的newComment 变量传递给this.props.getVideoComments() 动作创建者。代码如下:

CommentSection.js(我想更新我的状态)

 //redux stuff
import connect from 'react-redux'
import getVideoComments from '../actions'

class CommentsSection extends React.Component

    constructor(props)
        super(props)
        //this.state=comments:[], loading:false

    

    componentDidMount()
        this.props.getVideoComments()

    


    handleCommentSubmit = (newComment) =>
        // call action creator to dist action to all reducers and update relevant states
        this.props.getVideoComments()
        //this.setState(comments: [...this.state.comments, newComment])
        //this.setState(comments: newComments,console.log('The current state is now',this.state.comments));
        //comment is object with author and message. Add new comment to old comments
        //this.setState(comments:[...this.state.comments,newComment],console.log(this.state, 'state updated'))

    
    //Comments are create in comment form, passed up then sent down through commentList to individual comment rendering inside comment.js
// comment form oncommentsubmit running everytime it renders, not only on submital
    render()
        const comments = this.props
        console.log(comments)
        return(
            <div>
                <span><h4> Comments </h4></span>
                <div className="ui grid"> 


                    <div className = "right floated eight wide column" >
                        <CommentList comments=comments/> 
                    </div>
                    <div className="left floated eight wide column">

                        <CommentForm onCommentSubmit=this.handleCommentSubmit/>

                    </div>
                 </div>
             </div>

        )

    


//redux stuff
//called following state update
const mapStateToProps = (state) => 

    return comments:state.videoComments

export default connect(mapStateToProps,getVideoComments:getVideoComments)(CommentsSection)

index.js(用于动作创建者)

import React from 'react'

export const getVideoComments= ()=> 

    return (dispatch, getState)=> 

        const videoComments = getState().videoComments

        return (
            type: 'GET_VIDEO_COMMENTS',
            payload: videoComments
        )
    

videoCommentsReducer.js

import React from 'react'

 const videoCommentsReducer=function(state= [], action) // reads in previous state
    switch (action.type)
        case 'GET_VIDEO_COMMENTS':
            return action.payload //reducer will update state to be payload.videoComments. Action only describes what happened
                                         // reducer describes how what happened effects state. Could also use previous state and action to create new data
        default: 
            return state
    


export default videoCommentsReducer

index.js(在它们组合的 reducer 文件夹中)

import React from 'react'
import combineReducers from 'redux'
import videoCommentsReducer from './videoCommentsReducer'

export default combineReducers(
    videoComments:videoCommentsReducer
)

【问题讨论】:

欢迎,努力提出格式正确的问题! 【参考方案1】:

从您的动作创建者文件中,您似乎正在使用redux-thunk middleware,因此请确保导入此库并将其应用到商店中。这个codesandbox 展示了一个基于你的完整示例。

使用此thunk 时,请确保始终使用它提供的调度以将操作发送到商店。不要从绑定的动作创建者返回对象

export const getVideoComments = () => 
  return (dispatch, getState) => 
    const videoComments = getRandomComments();

    dispatch(
      type: "GET_VIDEO_COMMENTS",
      payload: videoComments
    );
  ;
;

另外,在这里使用getState 来获取视频cmets 是没有意义的。您只需一遍又一遍地用相同的状态更新商店。 getState 在您想与状态的不同部分进行交互时很有用,即在捕获您的操作类型的 reducer 之外。

【讨论】:

顺便说一句,如果你想调试你的应用程序,请使用像redux-logger这样的日志中间件【参考方案2】:

在您的 CommentSection.js 中使用 mapDispatchToProps,无需在您的操作创建器中使用 getState。

Action Creator

const getVideoComments = (comments) => (
   type: 'GET_VIDEO_COMMENTS',
   payload: comments,
);

CommentSection.js

// handleCommentSubmit
handleCommentSubmit = (newComment) => 
   this.props.getVideoComments(newComment); //pass comment to action then access newComment in reducer then add it to your state


mapDispatchToProps = (state) => 
   getVideoComments: (newComment) => dispatch(getVideoComments(newComment)),


export default connect(mapStateToProps, mapDispatchToProps)(CommentsSection);


Reducer.js

case 'GET_VIDEO_COMMENTS':
   return [...state, action.payload];

【讨论】:

啊对。所以你也可以将你自己定义的普通 JS 对象传递给动作创建者? 我对这里发生的事情感到很困惑。 redux 文档说mapDispatchToProps 接受的唯一参数是dispatchownProps。我也不确定你为什么要在mapDispatchToProps 中调度动作创建者而不是动作对象?最后,这不会只是用最新评论替换我的状态,而不是将其添加到其他评论中吗? Action creator 只是返回一个对象,所以它就像您将一个对象传递给您的调度一样。 mapDispatchToProps = (state) =&gt; getVideoComments: (newComment) =&gt; dispatch(getVideoComments(newComment)), getVideoComments: 是道具。然后你告诉它要调度什么动作,因此(newComment) =&gt; dispatch(getVideoComments(newComment)) @Sean 关于替换你在减速器中的当前状态,我在上面编辑了我的答案,以展示你如何编辑你的减速器,这样它就不会替换你当前的状态,只需添加新评论。跨度> 感谢您的回复。根据您的初步建议,我已经在我的回答中实现了这一点。我会将您的标记为解决方案,但是当我复制 mapDispatchToProps 时出现了一些错误【参考方案3】:

Thought id 将我的解决方案作为答案发布,因为它结合了两个答案的部分内容,但需要两者的一部分才能完全解决问题。

通过结合上述两个答案的部分内容,我能够完全解决问题。我按照 fctmolina 和 Rodrigo Amaral 的建议删除了 getState()。我还将动作创建器简化为返回一个 javascript 对象,而不是一个函数,因此不再需要包含 dispatch 函数或使用 redux-thunk。我将newComment 变量传递给我的动作创建器,然后将它与reducer 中的旧状态结合起来。该解决方案只需要简单地将mapDispatchToProps 定义为一个包含动作创建者getVideoComments 的JS 对象,这使它可以作为commentSection 的道具,并导致动作创建者在this.props.getVideoComments() 函数时被调度打了电话。这是修改后的代码:

CommentSection.js

import React from 'react'
import CommentList from './CommentList'
import CommentForm from './CommentForm'


//redux stuff
import connect from 'react-redux'
import getVideoComments from '../actions'

class CommentsSection extends React.Component

    constructor(props)
        super(props)
        //this.state=comments:[], loading:false

    

    componentDidMount()
        console.log(this.props.comments)
    


    handleCommentSubmit = (newComment) =>
        // call action creator to dist action to all reducers and update relevant states
        this.props.getVideoComments(newComment)

    
    //Comments are create in comment form, passed up then sent down through commentList to individual comment rendering inside comment.js
// comment form oncommentsubmit running everytime it renders, not only on submital
    render()
        const comments = this.props
        console.log(comments)
        return(
            <div>
                <span><h4> Comments </h4></span>
                <div className="ui grid"> 


                    <div className = "right floated eight wide column" >
                        <CommentList comments=comments/> 
                    </div>
                    <div className="left floated eight wide column">

                        <CommentForm onCommentSubmit=this.handleCommentSubmit/>

                    </div>
                 </div>
             </div>

        )

    


//redux stuff
//called following state update
const mapStateToProps = (state) => 

    return comments:state.videoComments


export default connect(mapStateToProps,getVideoComments:getVideoComments)(CommentsSection)

videoCommentsReducer.js

import React from 'react'

 const videoCommentsReducer=function(state= [], action) // reads in previous state
    switch (action.type)
        case 'GET_VIDEO_COMMENTS':
            return [...state, action.payload] //reducer will update state to be payload.videoComments. Action only describes what happened
                                         // reducer describes how what happened effects state. Could also use previous state and action to create new data
        default: 
            return state
    


export default videoCommentsReducer

index.js(用于动作创建者)

import React from 'react'

export const getVideoComments = (newComment) => 
    return(
        type: 'GET_VIDEO_COMMENTS',
        payload: newComment
    )
;

【讨论】:

在你的操作中不需要返回,因为 javascript 在箭头函数中实现了隐式返回。参考:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

以上是关于如何使用从子组件传递给组件的反应变量更新 redux 状态的主要内容,如果未能解决你的问题,请参考以下文章

如何将输入值从子表单组件传递到其父组件的状态以使用反应钩子提交?

将一个变量的值从子组件传递给两个父组件,vuejs? nuxt

将变量从子组件传递到父组件

如何在 nuxt.js 上从子组件获取父组件的值?

无法将数据从子功能组件传递到反应父组件(React.js)[重复]

如何在 ReactJS 中将更改的状态从子组件传递给其父组件