coming from 1
Is it possible to set a default value here?
const Header = (props: {
isAdmin: boolean = false,
dispatch: Function
}) => (
<Toolbar style={style.bar}>
...
It seems there is not support for the feature yet
Add support for destructuring parameters + default values
For now I am doing
const Header = ({isAdmin , dispatch}: {
isAdmin: boolean;
dispatch: Function
}) => (
<Toolbar style={style.bar}>
...
Header.defaultProps = {
isAdmin: false
}
Related
I work on local environment and I use Next like framework. I use flexmonster component for react (https://www.npmjs.com/package/react-flexmonster)
When I make some modifications the current flexmonster component shows me this error : this.TD[this.j5] is null
I know that Flexmonster works on CSR (client side rendering) and I used a custom debounce hook to wait before excute any flexmonster functions .
Flexmonster component code :
import { useRef } from 'react';
import dynamic from 'next/dynamic';
import useDebounce from '#hooks/useDebounce';
import 'flexmonster/flexmonster.css';
const DynamicFlexMonster = dynamic(() => import('react-flexmonster'), {
ssr: false,
});
const Flexmonster = ({
dataSource = [],
rows = [],
columns = [],
measures = [],
formats = {},
viewType,
gridType,
chartType,
}) => {
const flexmonsterDataStructure = {
dataSource: {
data: dataSource,
},
slice: {
rows,
columns,
measures,
},
options: {
viewType,
grid: {
type: gridType,
showHeader: false,
showTotals: false,
showGrandTotals: 'off',
},
chart: {
type: chartType,
},
showEmptyData: true,
},
formats,
};
const ref = useRef(null);
const [debounceReport, setDebounceReport] = useDebounce(null);
const onReportComplete = () => {
setDebounceReport(ref.current, 1000);
if (debounceReport) {
console.log('>>>>', ref.current.flexmonster.getReport());
}
};
return (
<>
<DynamicFlexMonster
ref={ref}
toolbar={false}
width="100%"
report={flexmonsterDataStructure}
reportcomplete={onReportComplete}
/>
</>
);
};
export default Flexmonster;
I was facing the same issue, the main problem is Flexmonster use the window element so when you are working with an SSR framework like Nextjs you will need to call the all page where you display your Flexmonster component as SSR: false.
From your code, you will have to call your Flexmonster component like this:
/* pages/my-flexmonster-component-page */
import dynamic from 'next/dynamic';
const Flexmonster = dynamic(() => import('#components/Flexmonster'), {
ssr: false,
});
export default function MyFlexmonsterComponentPage(){
return (
<>
<Flexmonster/>
</>
);
}
Here my redux state , the state has dynamic nested object name
const search = {
client :
{ result: [],
selected: null,
isLoading: false,
isSuccess: false,},
[dynamicKey] :
{ result: [],
selected: null,
isLoading: false,
isSuccess: false,},
[dynamicKey2] :
{ result: [],
selected: null,
isLoading: false,
isSuccess: false,}
};
I'm trying to get nested object by dynamic key , here is my selector code :
import { createSelector } from "reselect";
export const searchState = (state) => state.search;
export const selectSearch = (keyRef) =>
createSelector([searchState], (search) => search[keyRef]);
You forgot to ask the question but your code looks fine as it is. In the component you can use useMemo to not needlessly create the selector:
//renamed the selector to create...
export const createSelectSearch = (keyRef) =>
createSelector([searchState], (search) => search[keyRef]);
//compnent example
const MyComponent = ({keyRef}) => {
const selectSearch = React.useMemo(
()=>createSelector(keyRef),//create the selector when keyRef changes
[keyRef]
);
const result = useSelector(selectSearch)
return <jsx />
}
Some more information about this pattern can be found here
I'm hard fighting with Redux, trying to dispatch inputValue to a store. When I'm trying to do this I get Cannot read property 'add' of undefined error.
import React, { useState } from 'react';
import './SearchingBar.css'
import { connect } from 'react-redux'
import actions from '../../duck/actions'
const SearchingBar = ({shareToggleClass, props}) => {
const [toggleClass, setToggleClass] = useState(false);
const [query, setQuery] = useState('');
const search = event => {
if(event.key === "Enter") {
setToggleClass(true);
shareToggleClass({toggleClass})
props.add(query)
}
}
return (
<input type = "text"
placeholder = "Search.."
className = {toggleClass ? "Active" : "unActive"}
onChange = {e => setQuery(e.target.value)}
value = {query}
onKeyPress = {search}
/>
)
}
const mapStateToProps = state => ({
inputValue: state.inputValue
})
const mapDispatchToProps = dispatch => ({
addValue: inputValue => dispatch(actions.addValue(inputValue))
})
export default connect(mapStateToProps, mapDispatchToProps)(SearchingBar);
Pretty sure your component argument destructuring is wrong.
Currently, you have:
const SearchingBar = ({shareToggleClass, props}) => {
However, as written, this assumes that the one-and-only argument for this function, which is an object we normally refer to as props, also has a nested field named props. That's probably not correct.
If you're trying to grab out just the shareToggleClass field, and then access all remaining props field as an object named props, you should use "rest destructuring":
// The ... rest operator grabs all remaining fields, and puts them in a new object
const SearchingBar = ({shareToggleClass, ...props}) => {
Alternately, you could just destructure any remaining fields specifically that you need:
const SearchingBar = ({shareToggleClass, add}) => {
The other issue is that you likely don't have a props.add function anyway, because your mapDispatch is configured to create a prop named addValue:
const mapDispatchToProps = dispatch => ({
addValue: inputValue => dispatch(actions.addValue(inputValue))
})
Also got a couple suggestions on the React-Redux usage.
If you are going to use connect, we recommend using the "object shorthand" form of mapDispatch instead of writing it as a function:
const mapDispatch = {
addValue: actions.addValue
}
connect(mapState, mapDispatch)(MyComponent)
// or even just pass the `actions` object directly
connect(mapState, actions)(MyComponent)
But, we specifically recommend using the React-Redux hooks API as the default instead of connect:
const SearchingBar = () => {
const inputValue = useSelector(state => state.inputValue);
const dispatch = useDispatch()
const [toggleClass, setToggleClass] = useState(false);
const [query, setQuery] = useState('');
const search = event => {
if(event.key === "Enter") {
setToggleClass(true);
shareToggleClass({toggleClass})
dispatch(addValue(query))
}
}
return (
<input type = "text"
placeholder = "Search.."
className = {toggleClass ? "Active" : "unActive"}
onChange = {e => setQuery(e.target.value)}
value = {query}
onKeyPress = {search}
/>
)
}
I'm new to Ramda and just trying to wrap my head around it. So here is the function I want to rewrite in functional style:
const makeReducer = (state, action) => {
if (action.type === LOG_OUT) {
return rootReducer(undefined, action)
}
return rootReducer(state, action)
}
Here is what I end up with:
const isAction = type => R.compose(R.equals(type), R.prop('type'))
const makeReducer = (state, action) => {
const isLogOut = isAction(LOG_OUT)
return R.ifElse(isLogOut, rootReducer(undefined, action), rootReducer(state, action))(action)
}
I assume it's totally wrong as there are several duplications of action and rootReducer
Actually I don't see any reason to refactor your code: you're not mutating inputs and you use if to conditionally return outputs.
About rootReducer(undefined, action), I believe that you should use parameter destructuring:
const rootReducer = ({ state, action } = {}} => {
// Stuff here
}
That is, you may give either state or action, or both:
const makeReducer = ({ state, action }) => {
if (action.type === LOG_OUT) {
return rootReducer({ action })
}
return rootReducer({ state, action })
}
Also, consider using terniary to solve simple cases:
const makeReducer = ({ state, action }) =>
rootReducer( action.type === LOG_OUT ? { action } : { state, action } )
Finally, there could be yet another approach using tagged sums and folds. Since I don't work with React and/or Redux, I don't know if you could go with this approach but I believe that it's still interesting that you discover this alternative solution:
const tag = Symbol ( 'tag' )
// TaggedSum
const Action = {
logout: value => ( { [tag]: 'logout', value } ),
login: value => ( { [tag]: 'login', value } )
}
const foldAction = matches => action => {
const actionTag = action[ tag ]
const match = matches [ actionTag ]
return match ( action.value )
}
const state = { x: 1 }
const LOG_IN = 1
const LOG_OUT = 2
const logout = Action.logout ( { action: LOG_OUT, state } )
const login = Action.login ( { action: LOG_IN, state } )
const rootReducer = args => console.log ( args )
// Pattern matching
const matchAction = {
logout: ( { state } ) => rootReducer( { state } ),
login: rootReducer
}
const foldAction_ = foldAction( matchAction )
foldAction_ ( logout )
foldAction_ ( login )
You can get rid of the duplication fairly easily:
const makeReducer = (state, action) =>
rootReducer((action.type === LOG_OUT ? undefined : state), action)
That is really neither more nor less functional than the original. But it does have the advantage of reducing duplication, and of dealing only with expressions and not statements, which is sometimes a concern of functional techniques.
But there is one way in which it is clearly not functional. There is a free variable in your code: LOG_OUT. I'm guessing from the ALL_CAPS that this is meant to be a constant. But the function doesn't know that. So this function is not actually referentially transparent. It's possible that between invocations with the same parameters, someone changes the value of LOG_OUT and you could get different results.
This makes the function harder to test. (You can't just supply it the necessary parameters; you also have to have the correct value of LOG_OUT in scope.) And it makes it much harder to reason about.
An alternative without this issue is
const makeReducer = (state, action, types) =>
rootReducer((action.type === types.LOG_OUT ? undefined : state), action)
If you want to use pointfree style syntax for your code, you could do something like:
const initialState = {
text: 'initial text'
}
const rootReducer = R.curry((state, action) => {
// setting initial state could be improved
state = state || initialState
// your root reducer logic here
return state;
})
// R.last is here to grab the action in [state, action]
const isAction = type => R.compose(R.equals(type), R.prop('type'), R.last)
// first makes (state, action) into [state, action]
// before running R.cond
const makeReducer = R.compose(R.cond([
[isAction('LOG_OUT'), R.compose(rootReducer(undefined), R.last)],
// "default" action
[R.T, R.apply(rootReducer)]
]), R.pair)
const loggedOutState = makeReducer(
{ text: 'latest text'},
{ type: 'LOG_OUT'}
)
console.log(loggedOutState)
// => { text: 'initial text' }
const nextState = makeReducer(
{ text: 'latest text'},
{ type: 'ANY_ACTION'}
)
console.log(nextState)
// => { text: 'latest text' }
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
What's good about this solution is that you could easily extend makeReducer to handle more actions (since it's using R.cond -- which is like a switch statement).
I am using reselect and react redux. I am trying to make a selector for a basic modal implementation.
my selector is
const selectModal = (state) => state.get('modal');
which throws the error of
Cannot read property 'get' of undefined
edit: It has been requested I show how I call select modal, though it should make no difference.
const mapStateToProps = createStructuredSelector({
isVisible: selectModalIsVisible(),
});
const mapDispatchToProps = {
hideModal,
showModal
};
export default connect(mapStateToProps, mapDispatchToProps)(Modal);
I believe this means the modal state container is not being found
Perhaps I am setting up my reducer or store incorrectly. My reducer is
function modalReducer(state = initialState, action) {
switch (action.type) {
case HIDE_MODAL:
return state.set(
'isVisible', false);
case SHOW_MODAL:
return state.set(
'isVisible', true);
default:
return state;
}
}
which is combined with combine reducers into a glob
export default function createReducer(asyncReducers){
return combineReducers({
route: routeReducer,
auth: authReducer,
modal: modalReducer,
...asyncReducers
});
}
and then injected into my store
function configureStore(initialState = {}, history) {
const middlewares = [
sagaMiddleware,
routerMiddleware(history),
];
const enhancers = [
applyMiddleware(...middlewares),
]
const store = createStore(
createReducer(),
fromJS(initialState),
compose(...enhancers)
);
store.runSaga = sagaMiddleware.run;
//store.close = () => store.dispatch(END)
store.runSaga(sagas);
store.asyncReducers = {};
return store;
}
var initialState = {}
const store = configureStore(fromJS(initialState), browserHistory);
The error within reselect is at lines 73/74 params = dependencies.map
var selector = function selector(state, props) {
for (var _len4 = arguments.length, args = Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) {
args[_key4 - 2] = arguments[_key4];
}
var params = dependencies.map(function (dependency) {
return dependency.apply(undefined, [state, props].concat(args));
});
return memoizedResultFunc.apply(undefined, _toConsumableArray(params));
};
So what am I doing wrong, do I need to do something with immutableJS differently to access the modal, or is my setup for the app incorrect? Thank you in advance for your feedback.
If you're using selectModal like you're using selectModalIsVisible, then your syntax is wrong. I'm pretty sure createStructuredSelector does not understand () => (state) => state.get('modal'). It would only accept (state) => state.get('modal')
Typically, my usages of createStructuredSelector will look like either
const getThing = (state, props) => state.things[props.thingId];
const getModal = state => state.get('modal');
const mapStateToProps = createStructuredSelector({
thing: getThing, // notice no parens
modal: getModal, // notice no parens
})
OR if I need selector factories:
// just pretend this selector was more complicated and needed memoization
const makeGetThing = () => createSelector(
state => state.things,
(state, props) => props.thingId,
(things, thingId) => things[thingId]);
const getModal = state => state.get('modal');
const makeMapStateToProps = () => createStructuredSelector({
thing: makeGetThing(), // yes parens
modal: getModal, // no parens
})