import React from 'react';
import { Route, Redirect } from 'react-router';
import { useSelector } from 'react-redux';
import Wrapper from '../wrappers/Wrapper';
import { PageLoader } from '../ui/layout/Loader';
import { authSelectors } from '../../modules/auth/authSelectors';
import { configSelectors } from '../../modules/config/configSelectors';
import { REQUEST } from '../../config/constants';
import routing from '../../config/routing';
export default function AuthRoute({ pageName, ...rest }) {
const isAuth = useSelector(authSelectors.isAuth);
const { status } = useSelector(authSelectors.getLogin);
if (status === REQUEST) {
return (
<Wrapper pageName={pageName}>
<PageLoader/>
</Wrapper>
);
}
if (!isAuth) {
return <Redirect to={routing().login} />;
}
return (
<Wrapper pageName={pageName}>
<Route {...rest} />
</Wrapper>
);
}
//App.jsx
...
<Switch>
<WrappedRoute exact path={routing().login} component={Login} />
<AuthRoute exact path={routing().a} component={A} />
<AuthRoute exact path={routing().b} component={B} />
<AuthRoute exact path={routing().c} component={C} />
</Switch>
...
elem.classList.toggle(active)
при клике уберет этот класс, если он был, или добавит, если его не было. Ниже Антон Спирин написал более универсальный компонент, который будет подсвечивать нужный li в зависимости от pathname, и я думаю Вам это решение подойдет лучше, потому что здесь нужно еще убирать другие класcы .active и подсвечивать только по клику на нужный. <Link/>
, и написать банальную функцию:сlass Links extends React.Component {
toggleActive = ({currentTarget}) => {
currentTarget.classList.toggle('active');
}
render() {
<li onClick={this.toggleActive}>
<Link to="/">
<u>Главная</u>
</Link>
</li>
<li onClick={this.toggleActive}>
<Link to="/about">
<u>О нас</u>
</Link>
</li>
}
}
Могу предположить, что такая ситуация у меня слоилась из-за того, что я в основном пишу маленькие проекты, а в больших проектах это действительно как-то помогает, но я не могу представить такую ситуацию.
//action
export const fetchUserData = createAction('USER_DATA_FETCH');
export const getUserData = (id) => async (dispatch) => {
dispatch(fetchUserData({status: 'request'}));
try {
const res = await api.getUserAccount(id);
if (res.data.status === 'success') {
dispatch(fetchUserData({status: 'success', data: res.data.data}));
return res;
} else {
dispatch(fetchUserData({status: 'failure'}));
notification('error', res.data.message || res.statusText)
}
} catch (e) {
dispatch(fetchUserData({status: 'failure'}))
notification('error', e.message)
}
}
//reducer
const userDataFetchingState = handleActions({
[actions.fetchUserData](state, {payload}) {
return payload.status;
}
}, 'none');
const userDataFetch = handleActions({
[actions.fetchUserData](state, {payload}) {
if (payload.status === 'success') {
return payload.data;
} else {
return state;
}
}
}, {});
const userData = combineReducers({
status: userDataFetchingState,
data: userDataFetch
});
"scripts": {
"dev": "webpack-dev-server --mode development --open",
"build": "webpack --mode production"
},
"devDependencies": {
"clean-webpack-plugin": "^0.1.19",
"css-loader": "^0.28.11",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^1.1.11",
"node-sass": "^4.9.0",
"path": "^0.12.7",
"sass-loader": "^6.0.7",
"style-loader": "^0.20.3",
"webpack": "^4.9.1",
"webpack-cli": "^2.1.4",
"webpack-dev-server": "^3.1.4"
},
"main": "index.js"
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');
const extractSass = new ExtractTextPlugin({
filename: './css/styles.css',
disable: process.env.NODE_ENV === 'development'
});
const bundleAnalyzer = new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: 'localhost',
analyzerPort: 8888,
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: process.env.NODE_ENV !== 'development',
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
})
const cleanDist = new CleanWebpackPlugin(['dist']); // чистит /dist при каждом билде
let conf = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
sourceMapFilename: "sourcemaps/[file].map",
publicPath: 'dist/' // Для webpack-dev-server, чтобы запускать файлы из памяти на лету без build
},
devServer: {
overlay: true // Если будет ошибка, появится оверлей на странице
},
module: {
rules: [
{
test: /\.(js|jsx)$/, // regExp
loader: 'babel-loader',
exclude: '/node_modules' //исключение
},
{
test: /\.scss$/,
use: extractSass.extract({
fallback: 'style-loader', //если не сработает извлечение, то записать в js
use: ['css-loader', 'sass-loader']
})
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
}
]
},
plugins: [
cleanDist,
extractSass
]
};
module.exports = (env, options) => {
let production = options.mode === 'production';
conf.devtool = production ? 'source-map' : 'eval-sourcemap';
//смотрим какой mode при запуске, и выбираем какие соурс мапы писать
//eval - быстрее, но пишет в итоговый файл(больше вес)
return conf;
}