假设我正在编写Twitter克隆但更简单。这是“帖子”看起来像什么的图片
在帖子的底部,有一个我称之为Social Bar
的内容,其中包含3个按钮,comment
,message
和like
按钮。 comment
按钮可让用户对帖子发表评论,message
按钮可让用户向帖子的所有者发送消息,like
按钮可让用户“喜欢”帖子。按下like
按钮后,按钮的颜色将变为红色,再次按下该按钮会使其再次变为灰色。
到目前为止,我将Social Bar
设为一个纯组件,它有自己的state
:commentCount
,liked
,likeCount
( liked
表示此用户之前是否喜欢此帖子,如果是,liked
= true,因此,按下按钮like
按钮的颜色最初为红色,{{ 1}}和liked
属性会相应更改。
我的问题是,当用户按下帖子时,我会将他们带到另一个页面,在那里他们可以查看帖子上的评论,如下所示:
您可以在此likeCount
页面中看到用户也可以“喜欢”该帖子。如果用户决定“喜欢”帖子(Post Content
按钮为红色),则第一张图片中的like
按钮也应该更新。我该如何实现呢?目前,我正在使用like
,每当我想要发布帖子时,我都会向每个redux
广播“帖子的postId
,如果Social Bar
匹配,然后更新id
按钮。是的,它可以工作,但是,每次按like
按钮,颜色需要大约1秒钟才能更改。我想要的是立即改变按钮,如Twitter和Facebook。我该怎么做?
答案 0 :(得分:6)
您似乎没有按照预期的方式使用redux。
您应该使用redux store(https://redux.js.org/docs/basics/Store.html#store)管理状态,而不是让组件具有自己的状态。
下面你可以找到一个简单的反应应用程序。应用程序中有2个部分:"所有帖子"和"特定职位"。在"所有帖子"部分你可以看到5个帖子,每个帖子都有自己喜欢的按钮,喜欢计数器。在"特定帖子"它只呈现一个帖子(帖子#2)。
当您点击&#34时,查看所有内容是如何保持同步的。在帖子#2上,无论你点击哪一部分(所有帖子/特定帖子)。
const createStore = window.Redux.createStore;
const combineReducers = window.Redux.combineReducers;
const connect = window.ReactRedux.connect;
const Provider = window.ReactRedux.Provider;
const postsData = [
{ id: 1, likes: 0 },
{ id: 2, likes: 1 },
{ id: 3, likes: 0 },
{ id: 4, likes: 3 },
{ id: 5, likes: 2 },
];
// First, we're defining the initial state
const initialState = {
posts: postsData,
postsLikeCounters: postsData.reduce((out, post) => {
return {
...out,
[post.id]: post.likes
};
}, {})
};
// Then we're defining our reducers. Here I have 3 reducers:
// posts, postsLikes and postsLikeCounters
// Obviously you may want to use other data structures
function posts(state=posts, action) {
return state;
}
function postsLikes(state={}, action) {
switch (action.type) {
case 'LIKE_POST':
return {
...state,
[action.post.id]: true
};
case 'UNLIKE_POST':
return {
...state,
[action.post.id]: false
};
default:
return state;
}
}
function postsLikeCounters(state={}, action) {
let value;
switch (action.type) {
case 'LIKE_POST':
value = state[action.post.id] || 0;
return {
...state,
[action.post.id]: value + 1
};
case 'UNLIKE_POST':
value = state[action.post.id] || 0;
return {
...state,
[action.post.id]: Math.max(value - 1, 0)
};
default:
return state;
}
}
// Now we're combining all reducers into a single rootReducer
const rootReducer = combineReducers({
posts,
postsLikes,
postsLikeCounters
});
// With rootReducer and the initialState we're ready to create our store
// To put it simple - store is a single place to keep the whole application state (instead of keeping it in specific components)
const store = createStore(rootReducer, initialState);
// Now we're going to define our components
const Post = (props) => (
<div style={ {border:'1px solid #000', margin: 5} }>
<strong>Post #{props.post.id}</strong>
{props.liked ? (
<button onClick={()=>props.onUnlike(props.post)}>
Unlike
</button>
) : (
<button onClick={()=>props.onLike(props.post)}>
Like
</button>
)}
<span>({props.likes} likes)</span>
</div>
)
const Posts = (props) => (
<div>
{ props.posts.map(post => (
<Post
key={post.id}
post={post}
likes={props.postsLikeCounters[post.id]}
liked={props.postsLikes[post.id]}
onLike={props.onLike}
onUnlike={props.onUnlike} />
) ) }
</div>
);
// Define onLike and onUnlike actions
const onLike = (post) => ({ type: 'LIKE_POST', post });
const onUnlike = (post) => ({ type: 'UNLIKE_POST', post });
// Create components that uses redux's store to manage state
const PostsWithLikes = connect(
function(state){
return {
posts: state.posts,
postsLikes: state.postsLikes,
postsLikeCounters: state.postsLikeCounters
};
},
{
onLike,
onUnlike
}
)(Posts)
const SpecificPost = connect(
function(state, ownProps){
const id = ownProps.id;
const post = state.posts.find(post => post.id === id);
return {
post: post,
liked: state.postsLikes[id],
likes: state.postsLikeCounters[id]
};
},
{
onLike,
onUnlike
}
)(Post);
// And we're ready to put it all together:
const App = (
<Provider store={store}>
<div>
<h1>all posts:</h1>
<PostsWithLikes />
<div>
<h2>specific post:</h2>
<SpecificPost id={2} />
</div>
</div>
</Provider>
);
ReactDOM.render(
App,
document.getElementById('rootElement')
);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.7.2/redux.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.6/react-redux.js"></script>
<div id="rootElement"></div>
&#13;