【问题标题】:Simulate inheritance using functional programming in React Redux application在 React Redux 应用程序中使用函数式编程模拟继承
【发布时间】:2018-04-22 11:05:59
【问题描述】:

我有一个组件,我希望能够覆盖render 方法和该组件中的某些方法。在 React 中你不能使用继承。在函数式编程中可能有一种使用组合的方法,但是您实际上如何将渲染和所有方法组合成单独的组件。对于诸如componentDidUpdate 之类的 React 默认组件函数,您是否能够将其组合为一个单独的组件,然后将其引入高阶组件 (HoC)。如何在 HoC 的每个组成组件中传递或访问道具和状态。如果能找到以某种方式扩展组件并覆盖方法的示例,那就太好了。

【问题讨论】:

  • "在 React 中你不能使用继承" - 需要引用。

标签: reactjs inheritance functional-programming redux composition


【解决方案1】:

“使用函数式程序模拟继承-”停止,什么?你为什么要为自己选择这样的负担?

函数式编程不是翻译您在其他范式中了解的概念。在开始编写有意义的程序之前,您需要学习许多新东西。

这里有一些来自Brian Lonsdorf's React Rally 2016 presentation 的东西——它可能会告诉你彩虹尽头的底池是什么样子,但要做到这一点,一切都靠自己。

让功能风格焕然一新;把旧习惯留在门口。

const { withReducer } = Recompose

const Reducer = g =>
({
  fold: g,
  contramap: f =>
    Reducer((state, action) => g(state, f(action))),
  map: f =>
    Reducer((state, action) => f(g(state, action))),
  concat: o =>
    Reducer((state, action) => o.fold(g(state, action), action))
})

const appReducer = Reducer((state, action) => {
  switch (action.type) {
    case 'set_visibility_filter':
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
})

const todoReducer = Reducer((state, action) => {
  switch (action.type) {
    case 'new_todo':
      const t = { id: 0, title: action.payload.title }
      return Object.assign({}, state, {
        todos: state.todos.concat(t)
      })
    default:
      return state
  }
})

const Component = g =>
({
  fold: g,
  contramap: f =>
    Component(x => g(f(x))),
  concat: other =>
    Component(x => <div>{g(x)} {other.fold(x)}</div>)
})


const classToFn = C =>
	(props) => <C {...props} />
  
const Hoc = g =>
({
  fold: g,
  concat: other =>
    Hoc(x => g(other.fold(x)))
})

// Example
// ======================

const todoApp = appReducer.concat(todoReducer)
                .contramap(action => Object.assign({filter: 'all'}, action))
                .map(s => Object.assign({}, s, {lastUpdated: Date()}))

const hoc = Hoc(withReducer('state', 'dispatch', todoApp.fold, {todos: []}))

const Todos = hoc.fold(({ state, dispatch }) =>
  <div>
    <span>Filter: {state.visibilityFilter}</span>
    <ul>
      { state.todos.map((t, i) => <li key={i}>{t.title}</li>) }
    </ul>
    <button onClick={() =>
      dispatch({ type: 'new_todo', payload: {title: 'New todo'}})}>
      Add Todo
    </button>
    <button onClick={() =>
      dispatch({ type: 'set_visibility_filter' })}>
      Set Visibility
    </button>
  </div>
)

const TodoComp = Component(classToFn(Todos))

const Header = Component(s => <h1>Now Viewing {s}</h1>)

const ProfileLink = Component(u => <a href={`/users/${u.id}`}>{u.name}</a>)


const App = Header.contramap(s => s.pageName)
						.concat(TodoComp)
						.concat(ProfileLink.contramap(s => s.current_user))
            .fold({ pageName: 'Home',
                    current_user: {id: 2, name: 'Boris' } })

ReactDOM.render(
  App,
  document.getElementById('container')
)
<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/recompose/0.26.0/Recompose.min.js"></script>
<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

【讨论】:

    猜你喜欢
    • 2019-01-08
    • 2014-05-28
    • 2019-01-07
    • 2011-04-08
    • 1970-01-01
    • 2017-11-22
    • 1970-01-01
    • 2019-02-07
    • 1970-01-01
    相关资源
    最近更新 更多