Add custom component after searchbar in #react-navigation/native-stack - reactjs

I'm having the following design
Looking for a smart way to accomplish my mission using #react-navigation/native-stack
Requirements are the following:
Filters should be present after native search bar.
Screen title should automatically shrink/expand upon scroll. As it's done by default.
The problem is I don't see any proper place to put filters component to.
If I put it to content title animation doesn't work. It's always small because content's outer component should be a ScrollView or its ancestor like FlatList or SectionList. Nested ScrollView of the same direction are not supported too.
<View>
<FiltersComponent />
<SectionList ... />
</View>
If I put it like that title animation works, but filters go out of bounds on scroll.
<SectionList ListHeaderComponent={FiltersComponent} ... />
I tried even following, but title looks buggy, its both presentations (small and large) visible in the same time.
// set headerLargeTitle: true initially
<SectionList
onScroll={(e) => {
navigation.setOptions({ headerLargeTitle: e.nativeEvent.contentOffset.y === 0 });
}}
/>
Can anyone suggest something?

Related

How can I set the Overlay container property when using OverlayTrigger?

I'm using the OverlayTrigger component to get hover behavior for tooltips, and therefore not using the Overlay component directly. The Overlay component has a container property that I'd like to use to remedy the tooltip getting cut off by its natural container element.
I've attempted to pass a popperConfig object, but that's not working. I've also tried adding a container attribute to the OverlayTrigger component.
<Container fluid className='flex-fill' ref={rowContainer}>
...
<OverlayTrigger delay={{show: 500}} overlay={renderUserTooltip}
popperConfig={{container: rowContainer}}>
<FaUser/>
</OverlayTrigger>
How can I set the container for the Overlay when the Overlay component isn't directly used?
React bootstrap doesn't have a container prop or something similar (I mean it has a target prop but as this part of the docs suggests, for the OverlayTrigger the type is null, so it doesn't accept values and I don't think you can trick it to accept (and I don't think it would be wise to try).
But a pretty nice example, that shows some sort of a workaround in my opinion, can also be find in the docs, under customizing-trigger-behavior.
Starting from that example, if you need your trigger to be totally separated from the container an option is to just wrap everything in a big container that receives ({ ref, ...triggerHandler }) and all is left is to give your container the ref, and the trigger to your FaUser component. So something like:
<OverlayTrigger
placement="bottom"
overlay={<Tooltip id="button-tooltip-2">Check out this avatar</Tooltip>}
>
{({ containerRef, ...triggerHandler }) => (
<Container fluid className='flex-fill' ref={containerRef}>
...
<FaUser/>
</Container>
)}
</OverlayTrigger>
I also created a sandbox with a minimal reproducible example.

How to fix React Native ScrollView default at bottom

I'm trying to build a Chat App with React Native.
In the chat screen, there is a ScrollView for every message sent and received.
However, every time when I leave the screen and back in, the default of the ScrollView is at the top. I've written a function to scrollToEnd after rendered, but that is After Rendered, I need to set the ScrollView at the bottom before it actually shows.
I've tried (but users can see it scrolling as soon as it is rendered):
const scrollToBottom = () => {
scrollEl.current.scrollIntoView({ behavior: 'smooth'})
}
useEffect(() => {
scrollToBottom()
}, [scrollEl, loading, chatHistory])
return(
<ScrollView bottom={0} w="100%" bg="blueGray.100" inverted>
<VStack flex={1} w="100%" id="VStack">
{!loading && chatHistory.chats[roomId] && chatHistory.chats[roomId].length > 0 && chatHistory.chats[roomId].map((chat, index) =>
<ChatItem type={chat.type}
text={chat.text}
fromSelf={chat.fromSelf}
key={index}
/>
)}
<Box ref={scrollEl} />
</VStack>
</ScrollView>
)
I've tried:
Set scale: -1 at CSS, which actually invert the whole screen upside down.
Thus, I have to invert every single message to invert them back to the normal side.
Meanwhile, the scrolling is totally in the opposite way when you scroll by mouse or slide on the screen.
Any solutions or suggestions?
Thanks!
I hardly recommend you to use FlatList cause of the performance of the rendering list
https://reactnative.dev/docs/flatlist
Also in FlatList you can achieve what exactly you want
https://reactnative.dev/docs/flatlist#initialscrollindex
Even if you want better performance below library handle list better than FlatList
https://github.com/Flipkart/recyclerlistview

No component displayed when adding a custom label to a ReferenceLine in Recharts

I'm trying to add a custom label with a circular border to the right of a ReferenceLine as shown here https://imgur.com/a/svCsNVZ and as it says you can do in the docs here http://recharts.org/en-US/api/ReferenceLine#label .
The issue we’re having is that whenever we try to pass a component in here <ReferenceLine {...props} label={<CustomizedLabel />} /> nothing ever gets rendered, no matter what I try.
I can’t find any examples where they have specifically done this to a reference line label, but have managed to get the component passing functionality working for the data points, so I’m not sure where we’re going wrong here.
Currently, we can customise the label using an object but when passing our own element in nothing is rendered.
<ReferenceLine
y={dataLimits.lL}
stroke={Colors.red.hex}
strokeDasharray="3 3"
label={{
position: "right",
value: dataLimits.lL,
fill: "#595959",
fontSize: "0.75rem"
}}
ifOverflow="extendDomain"
/>
We want to convert this to
<ReferenceLine
y={dataLimits.lL}
stroke={Colors.red.hex}
strokeDasharray="3 3"
label={<LimitLabel />}
ifOverflow="extendDomain"
/>
where LimitLabel has the properties above but with a circular border.
No error messages appear on the console, and no components appear in the DOM where it should be.
This is a jsfiddle with our current implementation without the custom component, if that helps demonstrate
https://jsfiddle.net/rbyztucn/1/
The docs on recharts are really limited on this, but from my experiments and the idea from #rebecca on using SVG elements, I realised that the label prop on these ReferenceLine components expects an SVG element, not a React DOM element.
I will update this comment when I find out more on positioning these elements; I have a feeling I can use Recharts inbuilt locating utils to make this fairly easy.
A nice side effect of this is that you can pass SVG icons to these labels easily too.
This is probably late, but I ran into the same problem recently and managed do find a solution.
Like J Rhodes mentioned, the documentation is very vague on how to create customized labels using Recharts. The lib is great but the documentation does need some improvement.
As far as I've noticed, any label prop or even the <Label /> component itself can only render SVG elements by default. One way to overcome this limitation is by declaring a customized SVG element using <foreignObject> and a rendered React element as children, like this example:
const renderCustomLabel = ({ viewBox }) => (
<g>
<foreignObject x={0} y={0} width={100} height={100}>
<div>Your custom content goes here...</div>
</foreignObject>
</g>
)}
On the component (<ReferenceLine /> and <ReferenceDot /> as label prop and <Label /> as content prop) call, all you need is to pass the function reference like this:
<ReferenceLine label={renderCustomLabel} />
Ps: The viewBox prop gives dynamic access to the parent component position.

React Native FlatList items not rendering

I'm testing a FlatList nested in a Navigator and trying to learn how it works. The code below works fine:
<FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <Text>{item.key}</Text>}
horizontal={true}
/>
But this does not:
<FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <TextComp data={item}/>}
horizontal={true}
/>
TextComp is just a component that displays item.key and it works as intended when tested separately. The code is
<View>
<Text>{this.props.data.key}</Text>
</View>
I've also tried drawing borders around both components and it seems that the FlatList is definitely rendering, but the items are not.
I am testing on my Android device.
Update: I added console.log(this.props) statement to the TextComp component and it displays the props correctly, so the the correct data is being passed from the FlatList to TextComp, but TextComp is just not getting rendered.
Marcel Kalveram got the solution here after I compared his code with mine. Turns out, a height and width are required for the item to render correctly in the FlatList. The explanation I figured for this is that the item's dimensions are required to properly size the item within the FlatList. Similarly, an item's dimensions cannot be percentages since its parent is a FlatList, which has varying dimensions itself. Therefore, the solution to my problem was to add width and height style attributes to the item component. To make it automatically resize, I used built-in React Native Dimensions.

Semantic UI React side bar render pusher only on visibility change (redux/rematch)

I am using react and semantic. I am using the multiple sidebar example. The idea is that the left hand sidebar offers up some menu options, and then the right hand sidebar is the sub menu based on which option from the left menu is chosen. When a sub menu item is selected, a component is added to the Sidebar.Pusher, i.e displayed on the page.
It all works except re-rendering the content of the Sidebar.Pusher. This apparently only updates when the left hand side bar's visibility changes. I am using redux/rematch to handle state, and can see that the state that holds the content of the Sidebar.Pusher is being updated, but `render() is only being called when visibility changes of the sidebar.
The content of Sidebar.Pusher is an array, and I even tried displaying on the page the length of the array, which is being updated (pushed into) each time an item on the right hand sidebar is clicked. However this doesn't cause a render() to be fired, its literally when the left hand sidebar visibility changes.
Just to note, I did see this issue, however its from last year, and the answer wasn't enough for me to be able to fix the issue. Help would be appreciated.
Structure:
Index.js renders App.js, App.js renders Menu.js (which is a semantic set of tabs). One of the menu options is Sidebar.js which renders:
<Sidebar.Pushable as={Segment}>
<Sidebar
as={Menu}
animation="overlay"
direction="right"
inverted
vertical
visible={secondaryVisibility}
width="wide"
>
{focusedList.map((el, i) => {
return (
<Menu.Item key={i} as="a" onClick={() => this.addSegment(el)}>
<Article el={el} />
</Menu.Item>
)
})}
</Sidebar>
<Sidebar
as={Menu}
animation="overlay"
icon="labeled"
inverted
// onHide={this.handleSidebarHide}
vertical
visible={primaryVisibility}
width="wide"
>
<Menu.Item
onClick={() => this.changeTab(menuItem)}
as="a"
name="menuItem"
header
>
Menu Item
</Menu.Item>
</Sidebar>
<Sidebar.Pusher style={{ minHeight: "600px" }}>
<Segment basic>
{segments.map((el, i) => {
console.log(`el ${el}`)
return <Content key={i} segment={el} />
})}
</Segment>
</Sidebar.Pusher>
and all state (secondaryVisibility etc) is stored in rematch
Thanks
I haven't been able to identify the problem based on the code you've posted, could you provide more info such as the entire Sidebar.js and maybe what's in the Content component?. My guess would be that there's a HOC or lifecycle method getting in the way.
I've created a trivial example that seems to work fine, if I understand what you're trying to accomplish: https://codesandbox.io/s/myl6xpz9py
I got it. I forgot about immutability in state. Perhaps someone will benefit from this.
I was trying to update a state array with
let tmp = prevState.contract.segments
tmp.push(segment)
this.update({ segments: tmp })
However, this won't work as tmp is a reference to prevState.contract.segments, so this won't work, as pushing to tmp is equivelent to pushing to prevState.contract.segments.
you have to have a completely new array:
const tmp = [...prevState.contract.segments, segment]
this.update({ segments: tmp })
Now it works.

Resources