LoginSignup
6
11

More than 5 years have passed since last update.

Next.js + Redux sample 日本語訳

Posted at

https://github.com/zeit/next.js/wiki/Redux-example のGoogle翻訳ほぼそのままです :joy:

Usually splitting your app state into pages feels natural but sometimes you'll want to have global state for your app. This is an example on how you can use redux that also works with our universal rendering approach. This is just a way you can do it but it's not the only one.

通常、アプリの状態をページに分割するのは当然ですが、アプリのグローバルな状態を持ちたいこともあります。 これは、サーバーサイドレンダリングでも機能するreduxを使用する方法の例です。 これが唯一の方法というわけではなく、この以外にもやり方はあります。

In this example we are going to display a digital clock that updates every second. The first render is happening in the server and then the browser will take over. To illustrate this, the server rendered clock will have a different background color than the client one.

この例では、1秒ごとに更新されるデジタル時計を表示します。 最初のレンダリングがサーバーで行われ、ブラウザが引き継ぎます。 これを説明するために、サーバでレンダリングされた時計は、クライアントのものとは異なる背景色にします。

clock

Our page is located at pages/index.js so it will map the route /. To get the initial data for rendering we are implementing the static method getInitialProps, initializing the redux store and dispatching the required actions until we are ready to return the initial state to be rendered.

私たちのページは pages / index.js にありますので、 / をマップします。 レンダリングのための初期データを取得するには、静的メソッドgetInitialPropsを実装して、reduxストアを初期化し、レンダリングされる初期状態を返す準備ができるまで必要なアクションをディスパッチします。

The root component for the render method is the react-redux Provider that allows us to send the store down to children components so they can access to the state when required.

renderメソッドのルートコンポーネントはreact-redux Providerで、子コンポーネントにストアを送信して、必要なときに状態にアクセスできるようにします。

To pass the initial state from the server to the client we pass it as a prop called initialState so then it's available when the client takes over.

初期状態をサーバーからクライアントに渡すために、 initialState という名前のpropを渡します。そうすれば、クライアントが引き継ぐときに利用可能になります。

// pages/index.js

import React from 'react'
import { Provider } from 'react-redux'
import { reducer, initStore, startClock } from '../store'
import Clock from '../components/Clock'

export default class Counter extends React.Component {
  static getInitialProps ({ req }) {
    const isServer = !!req
    const store = initStore(reducer, null, isServer)
    store.dispatch({ type: 'TICK', ts: Date.now() })
    return  { initialState: store.getState(), isServer }
  }

  constructor (props) {
    super(props)
    this.store = initStore(reducer, props.initialState, props.isServer)
  }

  componentDidMount () {
    this.timer = this.store.dispatch(startClock())
  }

  componentWillUnmount () {
    clearInterval(this.timer)
  }

  render () {
    return (
      <Provider store={this.store}>
        <Clock />
      </Provider>
    )
  }
}

The trick here for supporting universal redux is to separate the cases for the client and the server. When we are on the server we want to create a new store every time, otherwise different users data will be mixed up. If we are in the client we want to use always the same store.

universal reduxをサポートするためのここのトリックは、クライアントとサーバーのケースを分離することです。 サーバー上にいるときに毎回新しいストアを作成する必要があります。そうしないと、異なるユーザーデータが混在します。 クライアントにいる場合は、常に同じストアを使用したいと考えています。

// store.js

import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'

export const reducer = (state = { lastUpdate: 0, light: false }, action) => {
  switch (action.type) {
    case 'TICK': return { lastUpdate: action.ts, light: !!action.light }
    default: return state
  }
}

export const startClock = () => dispatch => {
  setInterval(() => dispatch({ type: 'TICK', light: true, ts: Date.now() }), 800)
}

export const initStore = (reducer, initialState, isServer) => {
  if (isServer && typeof window === 'undefined') {
    return createStore(reducer, initialState, applyMiddleware(thunkMiddleware))
  } else {
    if (!window.store) {
      window.store = createStore(reducer, initialState, applyMiddleware(thunkMiddleware))
    }
    return window.store
  } 
}

The clock has access to the state using the connect function from react-redux. In this case Clock is a direct child from the page but it could be deep down the render tree.

クロックは、react-reduxのconnect関数を使用して状態にアクセスできます。 この場合、Clockはページからの直接の子ですが、レンダリングツリーの深くにあっても問題ありません。

// components/Clock.js

import React from 'react'
import { connect } from 'react-redux'
import { style, merge } from 'next/css'

export default connect(state => state)(({ lastUpdate, light }) => {
  return (
    <div className={merge(styles, style({ backgroundColor: light ? '#999' : '#000' }))}>
      {format(new Date(lastUpdate))}
    </div>
  )
})

const format = t => `${pad(t.getHours())}:${pad(t.getMinutes())}:${pad(t.getSeconds())}`

const pad = n => n < 10 ? `0${n}` : n

const styles = style({
  padding: '15px',
  display: 'inline-block',
  color: '#82FA58',
  font: '50px menlo, monaco, monospace'
})
6
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
11