通过React Native和Redux实现``像推文''功能的更好方法

K.W*_*.Wu 2 react-native redux

假设我正在编写一个Twitter克隆,但要简单得多。这是一张“帖子”的图片

在此处输入图片说明

在帖子的底部,有一个我称之为的Social Bar东西,其中包含3个按钮commentmessagelike按钮。comment按钮可让用户对帖子发表评论,message按钮可让用户向帖子所有者发送消息,like按钮可让用户“喜欢”帖子。按下like按钮时,按钮的颜色将变为红色,再次按下将使其变为灰色。

我至今是,我做Social Bar一个纯粹的成分,它有它自己statecommentCountlikedlikeCountliked表示该用户是否喜欢这个职位之前,如果是这样,liked= TRUE,因此,颜色like按钮,最初将红,在按下按钮,likedlikeCount特性将相应改变)。

我的问题是,当用户按下帖子时,我会将他们带到另一个页面,他们可以在其中查看帖子中的评论,如下所示: 在此处输入图片说明

您可以在此Post Content页面中看到,用户也可以“喜欢”该帖子。如果用户决定“喜欢”该帖子(like按钮将为红色),则like第一张图片中的按钮也应进行更新。我应该如何实施呢?目前,我正在使用redux,只要我“喜欢”帖子,就将帖子的“广播” postId到every Social Bar,如果id匹配,则更新like按钮。是的,它可以工作,但是,每当我按下like按钮时,颜色更改大约需要1秒钟。我想要的是按钮立即更改,例如Twitter和Facebook。我怎么做?

sla*_*iej 8

似乎您没有按照预期的方式使用redux。

与其让组件具有自己的状态,不如使用redux store(https://redux.js.org/docs/basics/Store.html#store)管理状态。

您可以在下面找到一个简单的react应用程序。应用程序中有2个部分:“所有帖子”和“特定帖子”。在“所有帖子”部分,您可以看到5个帖子,每个帖子都有自己的“喜欢”按钮和“喜欢”计数器。在“特定帖子”部分中,它仅呈现一个帖子(帖子#2)。

查看您在第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')
);
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)