实施 React Redux

Implementing React Redux

正在慢慢学习React,也在学习用Redux实现。但我似乎遇到了障碍。所以这就是我到目前为止所拥有的。

/index.jsx

import './main.css'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App.jsx'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import ShoppingList from './reducers/reducer'

let store = createStore(ShoppingList)

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('app')
)

/actions/items.js

import uuid from 'node-uuid'

export const CREATE_ITEM = 'CREATE_ITEM'
export function createItem(item) {
  return {
    type: CREATE_ITEM,
    item: {
      id: uuid.v4(),
      item,
      checked: false
    }
  }
}

/reducers/reducer.js

import * as types from '../actions/items'
import uuid from 'node-uuid'

const initialState = []

const items = (state = initialState, action) => {
  switch (action.type) {
    case types.CREATE_ITEM:
      return {
        id: uuid.v4(),
        ...item
      }
    default:
      return state;
  }
 }

 export default items

/reducers/index.js
更新:

import { combineReducers } from 'redux'
import items from './reducer'

const ShoppingList = combineReducers({
  items
})

export default ShoppingList

/components/Item.jsx

import React from 'react';
import uuid from 'node-uuid'

export default class Item extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      isEditing: false
    }
  }

  render() {
    if(this.state.isEditing) {
      return this.renderEdit();
    }

    return this.renderItem();
  }

  renderEdit = () => {
    return (
      <input type="text"
        ref={(event) => 
          (event ? event.selectionStart = this.props.text.length : null)
        }
        autoFocus={true}
        defaultValue={this.props.text}
        onBlur={this.finishEdit}
        onKeyPress={this.checkEnter} 
      />
    )
  };

  renderDelete = () => {
    return <button onClick={this.props.onDelete}>x</button>;
  };

  renderItem = () => {
    const onDelete = this.props.onDelete;

    return (
      <div onClick={this.edit}>
        <span>{this.props.text}</span>
        {onDelete ? this.renderDelete() : null }
      </div>
    );
  };

  edit = () => {
    this.setState({
      isEditing: true
    });
  };

  checkEnter = (e) => {
    if(e.key === 'Enter') {
      this.finishEdit(e);
    }
  };

  finishEdit = (e) => {
    const value = e.target.value;

    if(this.props.onEdit) {
      this.props.onEdit(value);

      this.setState({
        isEditing: false
      });
    }
  };
}

/components/Items.jsx

import React from 'react';
import Item from './Item.jsx';

export default ({items, onEdit, onDelete}) => {
  return (
    <ul>{items.map(item =>
      <li key={item.id}>
        <Item 
          text={item.text} 
          onEdit={onEdit.bind(null, item.id)}
          onDelete={onDelete.bind(null, item.id)}
        />
      </li>
    )}</ul>
  );
}
//  UPDATE: http://redux.js.org/docs/basics/UsageWithReact.html
// Is this necessary?
const mapStateToProps = (state) => {
  return {
    state
  }
}

Items = connect(
  mapStateToPros
)(Items) // `SyntaxError app/components/Items.jsx: "Items" is read-only`

//////////////////////////////////////
// Also tried it this way. 
//////////////////////////////////////
Items = connect()(Items)
export default Items // same error as above.

也试过了

export default connect(
  state => ({
    items: store.items
  })
)(Items) // `Uncaught TypeError: Cannot read property 'items' of undefined`

更新:

经过多次尝试,Gitter 中的@hedgerh 指出应该改为state.items。所以解决方案是

export default connect(
  state => ({
    items: state.items
  })
)(Items)

也归功于@azium。

/components/App.jsx

export default class App extends React.Component {
  render() {
    return (
     <div>
        <button onClick={this.addItem}>+</button>
          <Items />
      </div>
    ); 
  } 
}

为了正确实施它,我在这里遗漏了什么?现在它打破了 Items.jsx 中的 Uncaught TypeError: Cannot read property 'map' of undefined。我想这是有道理的,因为它似乎没有正确连接。这是应用程序的第一部分,第二部分将允许用户创建多个列表,这些列表包含许多项目。我可能不得不从 Item.jsx 中提取方法,因为 List.jsx 会做几乎相同的事情。谢谢

你不见了connect。这就是东西从您的商店到您的组件的方式。阅读文档中的容器部分 http://redux.js.org/docs/basics/UsageWithReact.html

import React from 'react'
import Item from './Item.jsx'

import { connect } from 'react-redux'

let Items = ({items, onEdit, onDelete}) => {
  return (
    <ul>{items.map(item =>
      <li key={item.id}>
        <Item 
          text={item.text} 
          onEdit={onEdit.bind(null, item.id)}
          onDelete={onDelete.bind(null, item.id)}
        />
      </li>
      })
  </ul>
  )
}

export default connect(
  state => ({
    items: state.items
  })
)(Items)

此外,您似乎期望从父级传递 onEditonDelete 函数,但您没有这样做,因此这些函数将是未定义的。