.createClass()
уже или скоро deprecated// types
const types = {
UPDATE_FIELD: 'UPDATE_FIELD',
};
//types
// operations
const updateField = (value, error) => (
{ type: types.UPDATE_FIELD, value, error }
);
// reducer
const initialState = {
values: {email: '', password: ''},
errors: { email: '', password: '' }
};
function someFormReducer(state = initialState, action) {
switch(action.type) {
case types.UPDATE_FIELD: {
return {
values: { ...state.values, ...action.value },
errors: { ...state.errors, ...action.error };
}
}
return state;
}
// reducer
// так примерно выглядит global store
{
...
...
form: {
login: {
values: {
email: '',
password: '',
},
errors: {
email: '',
password: ''
}
},
}
}
// так примерно выглядит global store
import React from 'react';
import { validateEmail, validatePassword } from 'someValidateLibrary';
import { connect } from 'react-redux';
import { browserHistory } from 'react-router';
import { updateField } from 'path to operations file (action creators)'
class SomeForm extends React.Component {
handleValueChange = (e) => {
const field = e.target.name;
let error = '';
if(field === 'email' && !validateEmail(field)) {
error = "You email is so bad, seriously!";
}
else if (!validationPassword(field) ) {
error = "Your password is sucks!"
}
this.props.dispatch(
updateField(
{ field: e.target.value.trim() },
{ field: error.trim() }
)
);
}
proccessForm = () => {
const { errors } = this.props;
// если ошибок больше нет, то переход на другой роут
if(!errors.email && !errors.password) {
browserHistory.push('/home');
} else {
// your code here
}
}
render() {
const { values, errros } = this.props;
return (
// some ui
<form onSubmit={this.proccessForm}>
<p class="form-field">
<input
type="email"
name="email"
onChange={this.handleValueChange}
value={values.email}
/>
<span>{errors.email}</span>
</p>
<p class="form-field">
<input
type="text"
name="password"
onChange={this.handleValueChange}
value={values.password}
/>
<span>{errors.password}</span>
</p>
<button
type="submit"
disabled={!values.email && !values.password}>
submit
</button>
</form>
);
}
}
const mapStateToProps = ({ form: { login } }) => (
{ values: login.values, errors: login.errors }
);
connect(mapDispatchToProps)(SomeForm);
assets
и потом после сборки туда же их и отправляешь. как-то это странно. возможно лучше создать папку/src/images
, а в конфиге{
test: /\.(jpg|jpeg|gif|png)$/,
include: path.resolve(__dirname, "src/images"),
loader:'url-loader?limit=1024&name=images/[name].[ext]'
}
body {
background: url(../../assets/back.jpg);
background-size: cover;
font-family: 'Open Sans', sans-serif;
}
this.props.data
определён как default props(не будет меняться), но в большинстве случаев будет(идёт из родительского state либо из глобального хранилища, то есть store). this.props.data
обновится, локальный state останется прежним. Придётся дергать componentWillRecieveProps
. handle = {this.test}
. Пробелов быть не должно.export default class Board extends React.Component {
test = () => {
console.log(this)
}
render(){
const temp = this.props.data.map((item, index) =>
<Task data={item} key={index} handle={this.test} />
)
return <div className="board">{temp}</div>
}
}
// Register server-side rendering middleware
app.get('*', (req, res) => {
if (__DEV__) {
webpackIsomorphicTools.refresh();
}
const store = configureStore();
// If __DISABLE_SSR__ = true, disable server side rendering
if (__DISABLE_SSR__) {
res.send(renderHtmlPage(store));
return;
}
const memoryHistory = createMemoryHistory(req.url);
const history = syncHistoryWithStore(memoryHistory, store, {
selectLocationState: state => state.get('routing').toJS(),
});
// eslint-disable-next-line max-len
match({history: memoryHistory, routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message);
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if (!renderProps) {
res.sendStatus(404);
} else {
// Dispatch the initial action of each container first
const promises = renderProps.components
.filter(component => component.fetchData)
.map(component => component.fetchData(store.dispatch, renderProps.params));
// Then render the routes
Promise.all(promises)
.then(() => {
// Using the enhanced history of react-redux-router to instead of the 'memoryHistory'
const props = Object.assign({}, renderProps, { history });
const content = renderToString(
<Provider store={store}>
<RouterContext {...props} />
</Provider>
);
res.status(200).send(renderHtmlPage(store, content));
});
}
});
});
class UsersPage extends React.Component {
static async fetchData(url) {
try {
const res = await axios.get(url);
const users = res.data
} catch(err) {
console.error(err.message);
}
}
componentDidMount() {
this.fetchData(url);
}
render() {
return (
// whatever
);
}
}
import { compose, createStore, combineReducers, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import * as reducers from './reducers';
import promises from './middlewares/promises';
const reducer = combineReducers(reducers);
const middlewares = [promises];
if(process.env.NODE_ENV === 'development') {
if(process.browser) {
middlewares.push(createLogger());
}
// другие миддлвары, которые использовать только в этой среде
}
const store = compose(applyMiddleware(...middlewares))(createStore)(reducer);
export default store;
class App extends React.Component {
toggle() {
this.page.classList.toggle('dark');
}
render() {
return (
<div
className="page"
ref={page => this.page = page}
>
<button
className=" center toggler"
onClick={this.toggle.bind(this)}
>
Toggle
</button>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
// ./index.js
const express = require('express')
const path = require('path')
const port = process.env.PORT || 3000
const app = express()
// serve static assets normally
app.use(express.static(__dirname + '/public'))
// Handles all routes so you do not get a not found error
app.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})
app.listen(port)
console.log("server started on port " + port)